summarylogtreecommitdiffstats
path: root/glibc-34fb5f61d3c3f4b8fc616ea259fa19168b58ecd4.patch
diff options
context:
space:
mode:
authorTavian Barnes2019-07-04 15:25:01 -0400
committerTavian Barnes2019-07-04 15:25:01 -0400
commit363e369b0d94b0b33328597f90a0a910056b7990 (patch)
treea3f72cff32e1581696b8928878e0cd0a13e18c19 /glibc-34fb5f61d3c3f4b8fc616ea259fa19168b58ecd4.patch
parentcbacff4f8fa16e713686e844f163c492c1c35333 (diff)
downloadaur-363e369b0d94b0b33328597f90a0a910056b7990.tar.gz
Bump to 2.29-3
Diffstat (limited to 'glibc-34fb5f61d3c3f4b8fc616ea259fa19168b58ecd4.patch')
-rw-r--r--glibc-34fb5f61d3c3f4b8fc616ea259fa19168b58ecd4.patch4059
1 files changed, 4059 insertions, 0 deletions
diff --git a/glibc-34fb5f61d3c3f4b8fc616ea259fa19168b58ecd4.patch b/glibc-34fb5f61d3c3f4b8fc616ea259fa19168b58ecd4.patch
new file mode 100644
index 000000000000..fa7f94c4a793
--- /dev/null
+++ b/glibc-34fb5f61d3c3f4b8fc616ea259fa19168b58ecd4.patch
@@ -0,0 +1,4059 @@
+diff --git a/ChangeLog b/ChangeLog
+index 59dab18463..20b650e026 100644
+--- a/ChangeLog
++++ b/ChangeLog
+@@ -1,3 +1,219 @@
++2019-06-20 Dmitry V. Levin <ldv@altlinux.org>
++ Florian Weimer <fweimer@redhat.com>
++
++ [BZ #24228]
++ * libio/genops.c (_IO_unbuffer_all)
++ [SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)]: Do not attempt to free wide
++ buffers and access _IO_FILE_complete members of legacy libio streams.
++ * libio/tst-bz24228.c: New file.
++ * libio/tst-bz24228.map: Likewise.
++ * libio/Makefile [build-shared] (tests): Add tst-bz24228.
++ [build-shared] (generated): Add tst-bz24228.mtrace and
++ tst-bz24228.check.
++ [run-built-tests && build-shared] (tests-special): Add
++ $(objpfx)tst-bz24228-mem.out.
++ (LDFLAGS-tst-bz24228, tst-bz24228-ENV): New variables.
++ ($(objpfx)tst-bz24228-mem.out): New rule.
++
++2019-03-13 Zack Weinberg <zackw@panix.com>
++
++ * scripts/check-obsolete-constructs.py: New test script.
++ * scripts/check-installed-headers.sh: Remove tests for
++ obsolete typedefs, superseded by check-obsolete-constructs.py.
++ * Rules: Run scripts/check-obsolete-constructs.py over $(headers)
++ as a special test. Update commentary.
++ * posix/bits/types.h (__SQUAD_TYPE, __S64_TYPE): Define as __int64_t.
++ (__UQUAD_TYPE, __U64_TYPE): Define as __uint64_t.
++ Update commentary.
++ * posix/sys/types.h (__u_intN_t): Remove.
++ (u_int8_t): Typedef using __uint8_t.
++ (u_int16_t): Typedef using __uint16_t.
++ (u_int32_t): Typedef using __uint32_t.
++ (u_int64_t): Typedef using __uint64_t.
++
++2019-04-18 Adhemerval Zanella <adhemerval.zanella@linaro.org>
++
++ * malloc/tst-memalign.c (do_test): Disable
++ -Walloc-size-larger-than= around tests of malloc with negative
++ sizes.
++ * malloc/tst-malloc-too-large.c (do_test): Likewise.
++
++2019-05-22 Wilco Dijkstra <wdijkstr@arm.com>
++
++ [BZ #24531]
++ * malloc/malloc.c (MAX_TCACHE_COUNT): New define.
++ (do_set_tcache_count): Only update if count is small enough.
++ * manual/tunables.texi (glibc.malloc.tcache_count): Document max value.
++
++2019-05-15 Mark Wielaard <mark@klomp.org>
++
++ [BZ#24476]
++ * dlfcn/dlerror.c (__dlerror_main_freeres): Guard using
++ __libc_once_get (once) and static_buf == NULL.
++ (__dlerror): Check we have a valid key, set result to static_buf
++ otherwise.
++
++2019-05-15 Andreas Schwab <schwab@suse.de>
++
++ [BZ #20568]
++ * libio/wfileops.c (_IO_wfile_sync): Correct last argument to
++ __codecvt_do_length.
++ * libio/Makefile (tests): Add tst-wfile-sync.
++ ($(objpfx)tst-wfile-sync.out): Depend on $(gen-locales).
++ * libio/tst-wfile-sync.c: New file.
++ * libio/tst-wfile-sync.input: New file.
++
++2019-04-23 Adhemerval Zanella <adhemerval.zanella@linaro.org>
++
++ [BZ #18035]
++ * elf/Makefile (tests-container): Add tst-pldd.
++ * elf/pldd-xx.c: Use _Static_assert in of pldd_assert.
++ (E(find_maps)): Avoid use alloca, use default read file operations
++ instead of explicit LFS names, and fix infinite loop.
++ * elf/pldd.c: Explicit set _FILE_OFFSET_BITS, cleanup headers.
++ (get_process_info): Use _Static_assert instead of assert, use default
++ directory operations instead of explicit LFS names, and free some
++ leadek pointers.
++ * elf/tst-pldd.c: New file.
++
++2019-04-17 Adhemerval Zanella <adhemerval.zanella@linaro.org>
++
++ * support/Makefile (libsupport-routines): Add support_subprocess,
++ xposix_spawn, xposix_spawn_file_actions_addclose, and
++ xposix_spawn_file_actions_adddup2.
++ (tst-support_capture_subprocess-ARGS): New rule.
++ * support/capture_subprocess.h (support_capture_subprogram): New
++ prototype.
++ * support/support_capture_subprocess.c (support_capture_subprocess):
++ Refactor to use support_subprocess and support_capture_poll.
++ (support_capture_subprogram): New function.
++ * support/tst-support_capture_subprocess.c (write_mode_to_str,
++ str_to_write_mode, test_common, parse_int, handle_restart,
++ do_subprocess, do_subprogram, do_multiple_tests): New functions.
++ (do_test): Add support_capture_subprogram tests.
++ * support/subprocess.h: New file.
++ * support/support_subprocess.c: Likewise.
++ * support/xposix_spawn.c: Likewise.
++ * support/xposix_spawn_file_actions_addclose.c: Likewise.
++ * support/xposix_spawn_file_actions_adddup2.c: Likewise.
++ * support/xspawn.h: Likewise.
++
++2019-04-09 Carlos O'Donell <carlos@redhat.com>
++ Kwok Cheung Yeung <kcy@codesourcery.com>
++
++ [BZ #16573]
++ * malloc/mtrace.c: Define prototypes for all hooks.
++ (set_default_hooks): New function.
++ (set_trace_hooks): Likewise.
++ (save_default_hooks): Likewise.
++ (tr_freehook): Use new s*_hooks functions.
++ (tr_mallochook): Likewise.
++ (tr_reallochook): Likewise.
++ (tr_memalignhook): Likewise.
++ (mtrace): Likewise.
++ (muntrace): Likewise.
++
++2019-04-02 TAMUKI Shoichi <tamuki@linet.gr.jp>
++
++ [BZ #22964]
++ * localedata/locales/ja_JP (LC_TIME): Add entry for the new Japanese
++ era.
++
++2019-03-02 TAMUKI Shoichi <tamuki@linet.gr.jp>
++
++ [BZ #24162]
++ * localedata/locales/ja_JP (LC_TIME): Change the offset for Taisho
++ gan-nen from 2 to 1. Problem reported by Morimitsu, Junji.
++
++2019-03-21 Stefan Liebler <stli@linux.ibm.com>
++
++ * sysdeps/s390/dl-procinfo.h (HWCAP_IMPORTANT):
++ Add HWCAP_S390_VX and HWCAP_S390_VXE.
++
++2019-01-31 Paul Eggert <eggert@cs.ucla.edu>
++
++ CVE-2019-9169
++ regex: fix read overrun [BZ #24114]
++ Problem found by AddressSanitizer, reported by Hongxu Chen in:
++ https://debbugs.gnu.org/34140
++ * posix/regexec.c (proceed_next_node):
++ Do not read past end of input buffer.
++
++2019-03-13 Stefan Liebler <stli@linux.ibm.com>
++
++ * elf/dl-sysdep.c (_dl_show_auxv): Remove condition and always
++ call _dl_procinfo.
++ * sysdeps/unix/sysv/linux/s390/dl-procinfo.h (_dl_procinfo):
++ Ignore types other than AT_HWCAP.
++ * sysdeps/sparc/dl-procinfo.h (_dl_procinfo): Likewise.
++ * sysdeps/unix/sysv/linux/i386/dl-procinfo.h (_dl_procinfo):
++ Likewise.
++ * sysdeps/powerpc/dl-procinfo.h (_dl_procinfo): Adjust comment
++ in the case of falling back to generic output mechanism.
++ * sysdeps/unix/sysv/linux/arm/dl-procinfo.h (_dl_procinfo):
++ Likewise.
++
++2019-02-15 Florian Weimer <fweimer@redhat.com>
++
++ [BZ #24211]
++ * nptl/pthread_join_common.c (__pthread_timedjoin_ex): Do not read
++ pd->result after the thread descriptor has been freed.
++
++2019-02-08 Florian Weimer <fweimer@redhat.com>
++
++ [BZ #24161]
++ * sysdeps/nptl/fork.h (__run_fork_handlers): Add multiple_threads
++ argument.
++ * nptl/register-atfork.c (__run_fork_handlers): Only perform
++ locking if the new do_locking argument is true.
++ * sysdeps/nptl/fork.c (__libc_fork): Pass multiple_threads to
++ __run_fork_handlers.
++
++2019-02-07 Stefan Liebler <stli@linux.ibm.com>
++
++ [BZ #24180]
++ * nptl/pthread_mutex_trylock.c (__pthread_mutex_trylock):
++ Add compiler barriers and comments.
++
++2019-02-05 Florian Weimer <fweimer@redhat.com>
++
++ [BZ #24164]
++ arm: Use "nr" constraint for Systemtap probes, to avoid the
++ compiler using memory operands for constants, due to the "o"
++ alternative in the default "nor" constraint.
++ * include/stap-probe.h [USE_STAP_PROBE]: Include
++ <stap-probe-machine.h>
++ * sysdeps/generic/stap-probe-machine.h: New file.
++ * sysdeps/arm/stap-probe-machine.h: Likewise.
++
++2019-02-04 H.J. Lu <hongjiu.lu@intel.com>
++
++ [BZ #24155]
++ CVE-2019-7309
++ * NEWS: Updated for CVE-2019-7309.
++ * sysdeps/x86_64/memcmp.S: Use RDX_LP for size. Clear the
++ upper 32 bits of RDX register for x32. Use unsigned Jcc
++ instructions, instead of signed.
++ * sysdeps/x86_64/x32/Makefile (tests): Add tst-size_t-memcmp-2.
++ * sysdeps/x86_64/x32/tst-size_t-memcmp-2.c: New test.
++
++2019-01-31 Carlos O'Donell <carlos@redhat.com>
++ Torvald Riegel <triegel@redhat.com>
++ Rik Prohaska <prohaska7@gmail.com>
++
++ [BZ# 23844]
++ * nptl/Makefile (tests): Add tst-rwlock-tryrdlock-stall, and
++ tst-rwlock-trywrlock-stall.
++ * nptl/pthread_rwlock_tryrdlock.c (__pthread_rwlock_tryrdlock):
++ Wake waiters if PTHREAD_RWLOCK_FUTEX_USED is set.
++ * nptl/pthread_rwlock_trywrlock.c (__pthread_rwlock_trywrlock):
++ Set __wrphase_fute to 1 only if we started the write phase.
++ * nptl/tst-rwlock-tryrdlock-stall.c: New file.
++ * nptl/tst-rwlock-trywrlock-stall.c: New file.
++ * support/Makefile (libsupport-routines): Add xpthread_rwlock_destroy.
++ * support/xpthread_rwlock_destroy.c: New file.
++ * support/xthread.h: Declare xpthread_rwlock_destroy.
++
+ 2019-01-31 Siddhesh Poyarekar <siddhesh@sourceware.org>
+
+ * version.h (RELEASE): Set to "stable".
+diff --git a/NEWS b/NEWS
+index 912a9bdc0f..68d88b1036 100644
+--- a/NEWS
++++ b/NEWS
+@@ -4,6 +4,39 @@ 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.29.1
++
++Major new features:
++
++* The entry for the new Japanese era has been added for ja_JP locale.
++
++The following bugs are resolved with this release:
++
++ [16573] malloc: Set and reset all hooks for tracing
++ [18035] Fix pldd hang
++ [20568] Fix crash in _IO_wfile_sync
++ [24155] x32 memcmp can treat positive length as 0 (if sign bit in RDX is set) (CVE-2019-7309)
++ [24164] Systemtap probes need to use "nr" constraint on 32-bit Arm
++ [24161] __run_fork_handlers self-deadlocks in malloc/tst-mallocfork2
++ [24211] Use-after-free in Systemtap probe in pthread_join
++ [24228] old x86 applications that use legacy libio crash on exit
++ [24476] dlfcn: Guard __dlerror_main_freeres with __libc_once_get (once)
++
++Security related changes:
++
++ CVE-2019-7309: x86-64 memcmp used signed Jcc instructions to check
++ size. For x86-64, memcmp on an object size larger than SSIZE_MAX
++ has undefined behavior. On x32, the size_t argument may be passed
++ in the lower 32 bits of the 64-bit RDX register with non-zero upper
++ 32 bits. When it happened with the sign bit of RDX register set,
++ memcmp gave the wrong result since it treated the size argument as
++ zero. Reported by H.J. Lu.
++
++ CVE-2019-9169: Attempted case-insensitive regular-expression match
++ via proceed_next_node in posix/regexec.c leads to heap-based buffer
++ over-read. Reported by Hongxu Chen.
++
+
+ Version 2.29
+
+diff --git a/Rules b/Rules
+index 1562f2ce6d..16afa6acaa 100644
+--- a/Rules
++++ b/Rules
+@@ -82,7 +82,8 @@ $(common-objpfx)dummy.c:
+ common-generated += dummy.o dummy.c
+
+ ifneq "$(headers)" ""
+-# Special test of all the installed headers in this directory.
++# Test that all of the headers installed by this directory can be compiled
++# in isolation.
+ tests-special += $(objpfx)check-installed-headers-c.out
+ libof-check-installed-headers-c := testsuite
+ $(objpfx)check-installed-headers-c.out: \
+@@ -93,6 +94,8 @@ $(objpfx)check-installed-headers-c.out: \
+ $(evaluate-test)
+
+ ifneq "$(CXX)" ""
++# If a C++ compiler is available, also test that they can be compiled
++# in isolation as C++.
+ tests-special += $(objpfx)check-installed-headers-cxx.out
+ libof-check-installed-headers-cxx := testsuite
+ $(objpfx)check-installed-headers-cxx.out: \
+diff --git a/dlfcn/dlerror.c b/dlfcn/dlerror.c
+index 27376582d0..ca42c126c1 100644
+--- a/dlfcn/dlerror.c
++++ b/dlfcn/dlerror.c
+@@ -72,9 +72,16 @@ __dlerror (void)
+ __libc_once (once, init);
+
+ /* Get error string. */
+- result = (struct dl_action_result *) __libc_getspecific (key);
+- if (result == NULL)
+- result = &last_result;
++ if (static_buf != NULL)
++ result = static_buf;
++ else
++ {
++ /* init () has been run and we don't use the static buffer.
++ So we have a valid key. */
++ result = (struct dl_action_result *) __libc_getspecific (key);
++ if (result == NULL)
++ result = &last_result;
++ }
+
+ /* Test whether we already returned the string. */
+ if (result->returned != 0)
+@@ -230,13 +237,19 @@ free_key_mem (void *mem)
+ void
+ __dlerror_main_freeres (void)
+ {
+- void *mem;
+ /* Free the global memory if used. */
+ check_free (&last_result);
+- /* Free the TSD memory if used. */
+- mem = __libc_getspecific (key);
+- if (mem != NULL)
+- free_key_mem (mem);
++
++ if (__libc_once_get (once) && static_buf == NULL)
++ {
++ /* init () has been run and we don't use the static buffer.
++ So we have a valid key. */
++ void *mem;
++ /* Free the TSD memory if used. */
++ mem = __libc_getspecific (key);
++ if (mem != NULL)
++ free_key_mem (mem);
++ }
+ }
+
+ struct dlfcn_hook *_dlfcn_hook __attribute__((nocommon));
+diff --git a/elf/Makefile b/elf/Makefile
+index 9cf5cd8dfd..e7457e809f 100644
+--- a/elf/Makefile
++++ b/elf/Makefile
+@@ -194,6 +194,7 @@ tests-internal += loadtest unload unload2 circleload1 \
+ tst-tls3 tst-tls6 tst-tls7 tst-tls8 tst-dlmopen2 \
+ tst-ptrguard1 tst-stackguard1 tst-libc_dlvsym \
+ tst-create_format1
++tests-container += tst-pldd
+ ifeq ($(build-hardcoded-path-in-tests),yes)
+ tests += tst-dlopen-aout
+ tst-dlopen-aout-no-pie = yes
+diff --git a/elf/dl-sysdep.c b/elf/dl-sysdep.c
+index 5f6c679a3f..5d19b100b2 100644
+--- a/elf/dl-sysdep.c
++++ b/elf/dl-sysdep.c
+@@ -328,14 +328,9 @@ _dl_show_auxv (void)
+ assert (AT_NULL == 0);
+ assert (AT_IGNORE == 1);
+
+- if (av->a_type == AT_HWCAP || av->a_type == AT_HWCAP2
+- || AT_L1I_CACHEGEOMETRY || AT_L1D_CACHEGEOMETRY
+- || AT_L2_CACHEGEOMETRY || AT_L3_CACHEGEOMETRY)
+- {
+- /* These are handled in a special way per platform. */
+- if (_dl_procinfo (av->a_type, av->a_un.a_val) == 0)
+- continue;
+- }
++ /* Some entries are handled in a special way per platform. */
++ if (_dl_procinfo (av->a_type, av->a_un.a_val) == 0)
++ continue;
+
+ if (idx < sizeof (auxvars) / sizeof (auxvars[0])
+ && auxvars[idx].form != unknown)
+diff --git a/elf/pldd-xx.c b/elf/pldd-xx.c
+index 547f840ee1..756f6d7a1c 100644
+--- a/elf/pldd-xx.c
++++ b/elf/pldd-xx.c
+@@ -23,10 +23,6 @@
+ #define EW_(e, w, t) EW__(e, w, _##t)
+ #define EW__(e, w, t) e##w##t
+
+-#define pldd_assert(name, exp) \
+- typedef int __assert_##name[((exp) != 0) - 1]
+-
+-
+ struct E(link_map)
+ {
+ EW(Addr) l_addr;
+@@ -39,12 +35,12 @@ struct E(link_map)
+ EW(Addr) l_libname;
+ };
+ #if CLASS == __ELF_NATIVE_CLASS
+-pldd_assert (l_addr, (offsetof (struct link_map, l_addr)
+- == offsetof (struct E(link_map), l_addr)));
+-pldd_assert (l_name, (offsetof (struct link_map, l_name)
+- == offsetof (struct E(link_map), l_name)));
+-pldd_assert (l_next, (offsetof (struct link_map, l_next)
+- == offsetof (struct E(link_map), l_next)));
++_Static_assert (offsetof (struct link_map, l_addr)
++ == offsetof (struct E(link_map), l_addr), "l_addr");
++_Static_assert (offsetof (struct link_map, l_name)
++ == offsetof (struct E(link_map), l_name), "l_name");
++_Static_assert (offsetof (struct link_map, l_next)
++ == offsetof (struct E(link_map), l_next), "l_next");
+ #endif
+
+
+@@ -54,10 +50,10 @@ struct E(libname_list)
+ EW(Addr) next;
+ };
+ #if CLASS == __ELF_NATIVE_CLASS
+-pldd_assert (name, (offsetof (struct libname_list, name)
+- == offsetof (struct E(libname_list), name)));
+-pldd_assert (next, (offsetof (struct libname_list, next)
+- == offsetof (struct E(libname_list), next)));
++_Static_assert (offsetof (struct libname_list, name)
++ == offsetof (struct E(libname_list), name), "name");
++_Static_assert (offsetof (struct libname_list, next)
++ == offsetof (struct E(libname_list), next), "next");
+ #endif
+
+ struct E(r_debug)
+@@ -69,16 +65,17 @@ struct E(r_debug)
+ EW(Addr) r_map;
+ };
+ #if CLASS == __ELF_NATIVE_CLASS
+-pldd_assert (r_version, (offsetof (struct r_debug, r_version)
+- == offsetof (struct E(r_debug), r_version)));
+-pldd_assert (r_map, (offsetof (struct r_debug, r_map)
+- == offsetof (struct E(r_debug), r_map)));
++_Static_assert (offsetof (struct r_debug, r_version)
++ == offsetof (struct E(r_debug), r_version), "r_version");
++_Static_assert (offsetof (struct r_debug, r_map)
++ == offsetof (struct E(r_debug), r_map), "r_map");
+ #endif
+
+
+ static int
+
+-E(find_maps) (pid_t pid, void *auxv, size_t auxv_size)
++E(find_maps) (const char *exe, int memfd, pid_t pid, void *auxv,
++ size_t auxv_size)
+ {
+ EW(Addr) phdr = 0;
+ unsigned int phnum = 0;
+@@ -104,12 +101,9 @@ E(find_maps) (pid_t pid, void *auxv, size_t auxv_size)
+ if (phdr == 0 || phnum == 0 || phent == 0)
+ error (EXIT_FAILURE, 0, gettext ("cannot find program header of process"));
+
+- EW(Phdr) *p = alloca (phnum * phent);
+- if (pread64 (memfd, p, phnum * phent, phdr) != phnum * phent)
+- {
+- error (0, 0, gettext ("cannot read program header"));
+- return EXIT_FAILURE;
+- }
++ EW(Phdr) *p = xmalloc (phnum * phent);
++ if (pread (memfd, p, phnum * phent, phdr) != phnum * phent)
++ error (EXIT_FAILURE, 0, gettext ("cannot read program header"));
+
+ /* Determine the load offset. We need this for interpreting the
+ other program header entries so we do this in a separate loop.
+@@ -129,24 +123,18 @@ E(find_maps) (pid_t pid, void *auxv, size_t auxv_size)
+ if (p[i].p_type == PT_DYNAMIC)
+ {
+ EW(Dyn) *dyn = xmalloc (p[i].p_filesz);
+- if (pread64 (memfd, dyn, p[i].p_filesz, offset + p[i].p_vaddr)
++ if (pread (memfd, dyn, p[i].p_filesz, offset + p[i].p_vaddr)
+ != p[i].p_filesz)
+- {
+- error (0, 0, gettext ("cannot read dynamic section"));
+- return EXIT_FAILURE;
+- }
++ error (EXIT_FAILURE, 0, gettext ("cannot read dynamic section"));
+
+ /* Search for the DT_DEBUG entry. */
+ for (unsigned int j = 0; j < p[i].p_filesz / sizeof (EW(Dyn)); ++j)
+ if (dyn[j].d_tag == DT_DEBUG && dyn[j].d_un.d_ptr != 0)
+ {
+ struct E(r_debug) r;
+- if (pread64 (memfd, &r, sizeof (r), dyn[j].d_un.d_ptr)
++ if (pread (memfd, &r, sizeof (r), dyn[j].d_un.d_ptr)
+ != sizeof (r))
+- {
+- error (0, 0, gettext ("cannot read r_debug"));
+- return EXIT_FAILURE;
+- }
++ error (EXIT_FAILURE, 0, gettext ("cannot read r_debug"));
+
+ if (r.r_map != 0)
+ {
+@@ -160,13 +148,10 @@ E(find_maps) (pid_t pid, void *auxv, size_t auxv_size)
+ }
+ else if (p[i].p_type == PT_INTERP)
+ {
+- interp = alloca (p[i].p_filesz);
+- if (pread64 (memfd, interp, p[i].p_filesz, offset + p[i].p_vaddr)
++ interp = xmalloc (p[i].p_filesz);
++ if (pread (memfd, interp, p[i].p_filesz, offset + p[i].p_vaddr)
+ != p[i].p_filesz)
+- {
+- error (0, 0, gettext ("cannot read program interpreter"));
+- return EXIT_FAILURE;
+- }
++ error (EXIT_FAILURE, 0, gettext ("cannot read program interpreter"));
+ }
+
+ if (list == 0)
+@@ -174,14 +159,16 @@ E(find_maps) (pid_t pid, void *auxv, size_t auxv_size)
+ if (interp == NULL)
+ {
+ // XXX check whether the executable itself is the loader
+- return EXIT_FAILURE;
++ exit (EXIT_FAILURE);
+ }
+
+ // XXX perhaps try finding ld.so and _r_debug in it
+-
+- return EXIT_FAILURE;
++ exit (EXIT_FAILURE);
+ }
+
++ free (p);
++ free (interp);
++
+ /* Print the PID and program name first. */
+ printf ("%lu:\t%s\n", (unsigned long int) pid, exe);
+
+@@ -192,47 +179,27 @@ E(find_maps) (pid_t pid, void *auxv, size_t auxv_size)
+ do
+ {
+ struct E(link_map) m;
+- if (pread64 (memfd, &m, sizeof (m), list) != sizeof (m))
+- {
+- error (0, 0, gettext ("cannot read link map"));
+- status = EXIT_FAILURE;
+- goto out;
+- }
++ if (pread (memfd, &m, sizeof (m), list) != sizeof (m))
++ error (EXIT_FAILURE, 0, gettext ("cannot read link map"));
+
+ EW(Addr) name_offset = m.l_name;
+- again:
+ while (1)
+ {
+- ssize_t n = pread64 (memfd, tmpbuf.data, tmpbuf.length, name_offset);
++ ssize_t n = pread (memfd, tmpbuf.data, tmpbuf.length, name_offset);
+ if (n == -1)
+- {
+- error (0, 0, gettext ("cannot read object name"));
+- status = EXIT_FAILURE;
+- goto out;
+- }
++ error (EXIT_FAILURE, 0, gettext ("cannot read object name"));
+
+ if (memchr (tmpbuf.data, '\0', n) != NULL)
+ break;
+
+ if (!scratch_buffer_grow (&tmpbuf))
+- {
+- error (0, 0, gettext ("cannot allocate buffer for object name"));
+- status = EXIT_FAILURE;
+- goto out;
+- }
++ error (EXIT_FAILURE, 0,
++ gettext ("cannot allocate buffer for object name"));
+ }
+
+- if (((char *)tmpbuf.data)[0] == '\0' && name_offset == m.l_name
+- && m.l_libname != 0)
+- {
+- /* Try the l_libname element. */
+- struct E(libname_list) ln;
+- if (pread64 (memfd, &ln, sizeof (ln), m.l_libname) == sizeof (ln))
+- {
+- name_offset = ln.name;
+- goto again;
+- }
+- }
++ /* The m.l_name and m.l_libname.name for loader linkmap points to same
++ values (since BZ#387 fix). Trying to use l_libname name as the
++ shared object name might lead to an infinite loop (BZ#18035). */
+
+ /* Skip over the executable. */
+ if (((char *)tmpbuf.data)[0] != '\0')
+@@ -242,7 +209,6 @@ E(find_maps) (pid_t pid, void *auxv, size_t auxv_size)
+ }
+ while (list != 0);
+
+- out:
+ scratch_buffer_free (&tmpbuf);
+ return status;
+ }
+diff --git a/elf/pldd.c b/elf/pldd.c
+index f3fac4e487..69629bd5d2 100644
+--- a/elf/pldd.c
++++ b/elf/pldd.c
+@@ -17,23 +17,17 @@
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+-#include <alloca.h>
++#define _FILE_OFFSET_BITS 64
++
+ #include <argp.h>
+-#include <assert.h>
+ #include <dirent.h>
+-#include <elf.h>
+-#include <errno.h>
+ #include <error.h>
+ #include <fcntl.h>
+ #include <libintl.h>
+-#include <link.h>
+-#include <stddef.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+-#include <string.h>
+ #include <unistd.h>
+ #include <sys/ptrace.h>
+-#include <sys/stat.h>
+ #include <sys/wait.h>
+ #include <scratch_buffer.h>
+
+@@ -76,14 +70,9 @@ static struct argp argp =
+ options, parse_opt, args_doc, doc, NULL, more_help, NULL
+ };
+
+-// File descriptor of /proc/*/mem file.
+-static int memfd;
+-
+-/* Name of the executable */
+-static char *exe;
+
+ /* Local functions. */
+-static int get_process_info (int dfd, long int pid);
++static int get_process_info (const char *exe, int dfd, long int pid);
+ static void wait_for_ptrace_stop (long int pid);
+
+
+@@ -102,8 +91,10 @@ main (int argc, char *argv[])
+ return 1;
+ }
+
+- assert (sizeof (pid_t) == sizeof (int)
+- || sizeof (pid_t) == sizeof (long int));
++ _Static_assert (sizeof (pid_t) == sizeof (int)
++ || sizeof (pid_t) == sizeof (long int),
++ "sizeof (pid_t) != sizeof (int) or sizeof (long int)");
++
+ char *endp;
+ errno = 0;
+ long int pid = strtol (argv[remaining], &endp, 10);
+@@ -119,25 +110,24 @@ main (int argc, char *argv[])
+ if (dfd == -1)
+ error (EXIT_FAILURE, errno, gettext ("cannot open %s"), buf);
+
+- struct scratch_buffer exebuf;
+- scratch_buffer_init (&exebuf);
++ /* Name of the executable */
++ struct scratch_buffer exe;
++ scratch_buffer_init (&exe);
+ ssize_t nexe;
+ while ((nexe = readlinkat (dfd, "exe",
+- exebuf.data, exebuf.length)) == exebuf.length)
++ exe.data, exe.length)) == exe.length)
+ {
+- if (!scratch_buffer_grow (&exebuf))
++ if (!scratch_buffer_grow (&exe))
+ {
+ nexe = -1;
+ break;
+ }
+ }
+ if (nexe == -1)
+- exe = (char *) "<program name undetermined>";
++ /* Default stack allocation is at least 1024. */
++ snprintf (exe.data, exe.length, "<program name undetermined>");
+ else
+- {
+- exe = exebuf.data;
+- exe[nexe] = '\0';
+- }
++ ((char*)exe.data)[nexe] = '\0';
+
+ /* Stop all threads since otherwise the list of loaded modules might
+ change while we are reading it. */
+@@ -155,8 +145,8 @@ main (int argc, char *argv[])
+ error (EXIT_FAILURE, errno, gettext ("cannot prepare reading %s/task"),
+ buf);
+
+- struct dirent64 *d;
+- while ((d = readdir64 (dir)) != NULL)
++ struct dirent *d;
++ while ((d = readdir (dir)) != NULL)
+ {
+ if (! isdigit (d->d_name[0]))
+ continue;
+@@ -182,7 +172,7 @@ main (int argc, char *argv[])
+
+ wait_for_ptrace_stop (tid);
+
+- struct thread_list *newp = alloca (sizeof (*newp));
++ struct thread_list *newp = xmalloc (sizeof (*newp));
+ newp->tid = tid;
+ newp->next = thread_list;
+ thread_list = newp;
+@@ -190,17 +180,22 @@ main (int argc, char *argv[])
+
+ closedir (dir);
+
+- int status = get_process_info (dfd, pid);
++ if (thread_list == NULL)
++ error (EXIT_FAILURE, 0, gettext ("no valid %s/task entries"), buf);
++
++ int status = get_process_info (exe.data, dfd, pid);
+
+- assert (thread_list != NULL);
+ do
+ {
+ ptrace (PTRACE_DETACH, thread_list->tid, NULL, NULL);
++ struct thread_list *prev = thread_list;
+ thread_list = thread_list->next;
++ free (prev);
+ }
+ while (thread_list != NULL);
+
+ close (dfd);
++ scratch_buffer_free (&exe);
+
+ return status;
+ }
+@@ -281,9 +276,10 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
+
+
+ static int
+-get_process_info (int dfd, long int pid)
++get_process_info (const char *exe, int dfd, long int pid)
+ {
+- memfd = openat (dfd, "mem", O_RDONLY);
++ /* File descriptor of /proc/<pid>/mem file. */
++ int memfd = openat (dfd, "mem", O_RDONLY);
+ if (memfd == -1)
+ goto no_info;
+
+@@ -333,9 +329,9 @@ get_process_info (int dfd, long int pid)
+
+ int retval;
+ if (e_ident[EI_CLASS] == ELFCLASS32)
+- retval = find_maps32 (pid, auxv, auxv_size);
++ retval = find_maps32 (exe, memfd, pid, auxv, auxv_size);
+ else
+- retval = find_maps64 (pid, auxv, auxv_size);
++ retval = find_maps64 (exe, memfd, pid, auxv, auxv_size);
+
+ free (auxv);
+ close (memfd);
+diff --git a/elf/tst-pldd.c b/elf/tst-pldd.c
+new file mode 100644
+index 0000000000..ed19cedd05
+--- /dev/null
++++ b/elf/tst-pldd.c
+@@ -0,0 +1,118 @@
++/* Basic tests for pldd program.
++ Copyright (C) 2019 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, see
++ <http://www.gnu.org/licenses/>. */
++
++#include <stdio.h>
++#include <string.h>
++#include <unistd.h>
++#include <stdint.h>
++#include <libgen.h>
++#include <stdbool.h>
++
++#include <array_length.h>
++#include <gnu/lib-names.h>
++
++#include <support/subprocess.h>
++#include <support/capture_subprocess.h>
++#include <support/check.h>
++
++static void
++target_process (void *arg)
++{
++ pause ();
++}
++
++/* The test runs in a container because pldd does not support tracing
++ a binary started by the loader iself (as with testrun.sh). */
++
++static int
++do_test (void)
++{
++ /* Create a copy of current test to check with pldd. */
++ struct support_subprocess target = support_subprocess (target_process, NULL);
++
++ /* Run 'pldd' on test subprocess. */
++ struct support_capture_subprocess pldd;
++ {
++ /* Three digits per byte plus null terminator. */
++ char pid[3 * sizeof (uint32_t) + 1];
++ snprintf (pid, array_length (pid), "%d", target.pid);
++
++ const char prog[] = "/usr/bin/pldd";
++
++ pldd = support_capture_subprogram (prog,
++ (char *const []) { (char *) prog, pid, NULL });
++
++ support_capture_subprocess_check (&pldd, "pldd", 0, sc_allow_stdout);
++ }
++
++ /* Check 'pldd' output. The test is expected to be linked against only
++ loader and libc. */
++ {
++ pid_t pid;
++ char buffer[512];
++#define STRINPUT(size) "%" # size "s"
++
++ FILE *out = fmemopen (pldd.out.buffer, pldd.out.length, "r");
++ TEST_VERIFY (out != NULL);
++
++ /* First line is in the form of <pid>: <full path of executable> */
++ TEST_COMPARE (fscanf (out, "%u: " STRINPUT (512), &pid, buffer), 2);
++
++ TEST_COMPARE (pid, target.pid);
++ TEST_COMPARE (strcmp (basename (buffer), "tst-pldd"), 0);
++
++ /* It expects only one loader and libc loaded by the program. */
++ bool interpreter_found = false, libc_found = false;
++ while (fgets (buffer, array_length (buffer), out) != NULL)
++ {
++ /* Ignore vDSO. */
++ if (buffer[0] != '/')
++ continue;
++
++ /* Remove newline so baseline (buffer) can compare against the
++ LD_SO and LIBC_SO macros unmodified. */
++ if (buffer[strlen(buffer)-1] == '\n')
++ buffer[strlen(buffer)-1] = '\0';
++
++ if (strcmp (basename (buffer), LD_SO) == 0)
++ {
++ TEST_COMPARE (interpreter_found, false);
++ interpreter_found = true;
++ continue;
++ }
++
++ if (strcmp (basename (buffer), LIBC_SO) == 0)
++ {
++ TEST_COMPARE (libc_found, false);
++ libc_found = true;
++ continue;
++ }
++ }
++ TEST_COMPARE (interpreter_found, true);
++ TEST_COMPARE (libc_found, true);
++
++ fclose (out);
++ }
++
++ support_capture_subprocess_free (&pldd);
++ support_process_terminate (&target);
++
++ return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/include/stap-probe.h b/include/stap-probe.h
+index c53dd86592..8c26292edd 100644
+--- a/include/stap-probe.h
++++ b/include/stap-probe.h
+@@ -21,6 +21,7 @@
+
+ #ifdef USE_STAP_PROBE
+
++# include <stap-probe-machine.h>
+ # include <sys/sdt.h>
+
+ /* Our code uses one macro LIBC_PROBE (name, n, arg1, ..., argn).
+diff --git a/libio/Makefile b/libio/Makefile
+index 5bee83e55c..9626a16b01 100644
+--- a/libio/Makefile
++++ b/libio/Makefile
+@@ -65,7 +65,7 @@ tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc \
+ tst-setvbuf1 tst-popen1 tst-fgetwc bug-wsetpos tst-fseek \
+ tst-fwrite-error tst-ftell-partial-wide tst-ftell-active-handler \
+ tst-ftell-append tst-fputws tst-bz22415 tst-fgetc-after-eof \
+- tst-sprintf-ub tst-sprintf-chk-ub
++ tst-sprintf-ub tst-sprintf-chk-ub tst-wfile-sync
+
+ tests-internal = tst-vtables tst-vtables-interposed tst-readline
+
+@@ -73,6 +73,9 @@ ifeq (yes,$(build-shared))
+ # Add test-fopenloc only if shared library is enabled since it depends on
+ # shared localedata objects.
+ tests += tst-fopenloc
++# Add tst-bz24228 only if shared library is enabled since it can never meet its
++# objective with static linking because the relevant code just is not there.
++tests += tst-bz24228
+ endif
+ test-srcs = test-freopen
+
+@@ -157,11 +160,14 @@ CFLAGS-tst_putwc.c += -DOBJPFX=\"$(objpfx)\"
+ CFLAGS-tst-sprintf-ub.c += -Wno-restrict
+ CFLAGS-tst-sprintf-chk-ub.c += -Wno-restrict
+
++LDFLAGS-tst-bz24228 = -Wl,--version-script=tst-bz24228.map
++
+ tst_wprintf2-ARGS = "Some Text"
+
+ test-fmemopen-ENV = MALLOC_TRACE=$(objpfx)test-fmemopen.mtrace
+ tst-fopenloc-ENV = MALLOC_TRACE=$(objpfx)tst-fopenloc.mtrace
+ tst-bz22415-ENV = MALLOC_TRACE=$(objpfx)tst-bz22415.mtrace
++tst-bz24228-ENV = MALLOC_TRACE=$(objpfx)tst-bz24228.mtrace
+
+ generated += test-fmemopen.mtrace test-fmemopen.check
+ generated += tst-fopenloc.mtrace tst-fopenloc.check
+@@ -170,6 +176,7 @@ generated += tst-bz22415.mtrace tst-bz22415.check
+ aux := fileops genops stdfiles stdio strops
+
+ ifeq ($(build-shared),yes)
++generated += tst-bz24228.mtrace tst-bz24228.check
+ aux += oldfileops oldstdfiles
+ endif
+
+@@ -184,7 +191,8 @@ tests-special += $(objpfx)test-freopen.out $(objpfx)test-fmemopen-mem.out \
+ ifeq (yes,$(build-shared))
+ # Run tst-fopenloc-cmp.out and tst-openloc-mem.out only if shared
+ # library is enabled since they depend on tst-fopenloc.out.
+-tests-special += $(objpfx)tst-fopenloc-cmp.out $(objpfx)tst-fopenloc-mem.out
++tests-special += $(objpfx)tst-fopenloc-cmp.out $(objpfx)tst-fopenloc-mem.out \
++ $(objpfx)tst-bz24228-mem.out
+ endif
+ endif
+
+@@ -212,6 +220,7 @@ $(objpfx)tst-ungetwc1.out: $(gen-locales)
+ $(objpfx)tst-ungetwc2.out: $(gen-locales)
+ $(objpfx)tst-widetext.out: $(gen-locales)
+ $(objpfx)tst_wprintf2.out: $(gen-locales)
++$(objpfx)tst-wfile-sync.out: $(gen-locales)
+ endif
+
+ $(objpfx)test-freopen.out: test-freopen.sh $(objpfx)test-freopen
+@@ -235,3 +244,7 @@ $(objpfx)tst-fopenloc-mem.out: $(objpfx)tst-fopenloc.out
+ $(objpfx)tst-bz22415-mem.out: $(objpfx)tst-bz22415.out
+ $(common-objpfx)malloc/mtrace $(objpfx)tst-bz22415.mtrace > $@; \
+ $(evaluate-test)
++
++$(objpfx)tst-bz24228-mem.out: $(objpfx)tst-bz24228.out
++ $(common-objpfx)malloc/mtrace $(objpfx)tst-bz24228.mtrace > $@; \
++ $(evaluate-test)
+diff --git a/libio/genops.c b/libio/genops.c
+index 2a0d9b81df..11a15549e8 100644
+--- a/libio/genops.c
++++ b/libio/genops.c
+@@ -789,9 +789,16 @@ _IO_unbuffer_all (void)
+
+ for (fp = (FILE *) _IO_list_all; fp; fp = fp->_chain)
+ {
++ int legacy = 0;
++
++#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)
++ if (__glibc_unlikely (_IO_vtable_offset (fp) != 0))
++ legacy = 1;
++#endif
++
+ if (! (fp->_flags & _IO_UNBUFFERED)
+ /* Iff stream is un-orientated, it wasn't used. */
+- && fp->_mode != 0)
++ && (legacy || fp->_mode != 0))
+ {
+ #ifdef _IO_MTSAFE_IO
+ int cnt;
+@@ -805,7 +812,7 @@ _IO_unbuffer_all (void)
+ __sched_yield ();
+ #endif
+
+- if (! dealloc_buffers && !(fp->_flags & _IO_USER_BUF))
++ if (! legacy && ! dealloc_buffers && !(fp->_flags & _IO_USER_BUF))
+ {
+ fp->_flags |= _IO_USER_BUF;
+
+@@ -816,7 +823,7 @@ _IO_unbuffer_all (void)
+
+ _IO_SETBUF (fp, NULL, 0);
+
+- if (fp->_mode > 0)
++ if (! legacy && fp->_mode > 0)
+ _IO_wsetb (fp, NULL, NULL, 0);
+
+ #ifdef _IO_MTSAFE_IO
+@@ -827,7 +834,8 @@ _IO_unbuffer_all (void)
+
+ /* Make sure that never again the wide char functions can be
+ used. */
+- fp->_mode = -1;
++ if (! legacy)
++ fp->_mode = -1;
+ }
+
+ #ifdef _IO_MTSAFE_IO
+diff --git a/libio/tst-bz24228.c b/libio/tst-bz24228.c
+new file mode 100644
+index 0000000000..6a74500d47
+--- /dev/null
++++ b/libio/tst-bz24228.c
+@@ -0,0 +1,29 @@
++/* BZ #24228 check for memory corruption in legacy libio
++ Copyright (C) 2019 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for 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 <mcheck.h>
++#include <support/test-driver.h>
++
++static int
++do_test (void)
++{
++ mtrace ();
++ return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/libio/tst-bz24228.map b/libio/tst-bz24228.map
+new file mode 100644
+index 0000000000..4383e0817d
+--- /dev/null
++++ b/libio/tst-bz24228.map
+@@ -0,0 +1,5 @@
++# Hide the symbol from libc.so.6 to switch to the libio/oldfileops.c
++# implementation when it is available for the architecture.
++{
++ local: _IO_stdin_used;
++};
+diff --git a/libio/tst-wfile-sync.c b/libio/tst-wfile-sync.c
+new file mode 100644
+index 0000000000..618682064d
+--- /dev/null
++++ b/libio/tst-wfile-sync.c
+@@ -0,0 +1,39 @@
++/* Test that _IO_wfile_sync does not crash (bug 20568).
++ Copyright (C) 2019 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, see
++ <http://www.gnu.org/licenses/>. */
++
++#include <locale.h>
++#include <stdio.h>
++#include <wchar.h>
++#include <support/check.h>
++#include <support/xunistd.h>
++
++static int
++do_test (void)
++{
++ TEST_VERIFY_EXIT (setlocale (LC_ALL, "de_DE.UTF-8") != NULL);
++ /* Fill the stdio buffer and advance the read pointer. */
++ TEST_VERIFY_EXIT (fgetwc (stdin) != WEOF);
++ /* This calls _IO_wfile_sync, it should not crash. */
++ TEST_VERIFY_EXIT (setvbuf (stdin, NULL, _IONBF, 0) == 0);
++ /* Verify that the external file offset has been synchronized. */
++ TEST_COMPARE (xlseek (0, 0, SEEK_CUR), 1);
++
++ return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/libio/tst-wfile-sync.input b/libio/tst-wfile-sync.input
+new file mode 100644
+index 0000000000..12d0958f7a
+--- /dev/null
++++ b/libio/tst-wfile-sync.input
+@@ -0,0 +1 @@
++This is a test of _IO_wfile_sync.
+diff --git a/libio/wfileops.c b/libio/wfileops.c
+index 78f20486e5..bab2ba4892 100644
+--- a/libio/wfileops.c
++++ b/libio/wfileops.c
+@@ -508,11 +508,12 @@ _IO_wfile_sync (FILE *fp)
+ generate the wide characters up to the current reading
+ position. */
+ int nread;
+-
++ size_t wnread = (fp->_wide_data->_IO_read_ptr
++ - fp->_wide_data->_IO_read_base);
+ fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
+ nread = (*cv->__codecvt_do_length) (cv, &fp->_wide_data->_IO_state,
+ fp->_IO_read_base,
+- fp->_IO_read_end, delta);
++ fp->_IO_read_end, wnread);
+ fp->_IO_read_ptr = fp->_IO_read_base + nread;
+ delta = -(fp->_IO_read_end - fp->_IO_read_base - nread);
+ }
+diff --git a/localedata/locales/ja_JP b/localedata/locales/ja_JP
+index 1fd2fee44b..c64aaaff55 100644
+--- a/localedata/locales/ja_JP
++++ b/localedata/locales/ja_JP
+@@ -14946,12 +14946,14 @@ am_pm "<U5348><U524D>";"<U5348><U5F8C>"
+
+ t_fmt_ampm "%p%I<U6642>%M<U5206>%S<U79D2>"
+
+-era "+:2:1990//01//01:+*:<U5E73><U6210>:%EC%Ey<U5E74>";/
++era "+:2:2020//01//01:+*:<U4EE4><U548C>:%EC%Ey<U5E74>";/
++ "+:1:2019//05//01:2019//12//31:<U4EE4><U548C>:%EC<U5143><U5E74>";/
++ "+:2:1990//01//01:2019//04//30:<U5E73><U6210>:%EC%Ey<U5E74>";/
+ "+:1:1989//01//08:1989//12//31:<U5E73><U6210>:%EC<U5143><U5E74>";/
+ "+:2:1927//01//01:1989//01//07:<U662D><U548C>:%EC%Ey<U5E74>";/
+ "+:1:1926//12//25:1926//12//31:<U662D><U548C>:%EC<U5143><U5E74>";/
+ "+:2:1913//01//01:1926//12//24:<U5927><U6B63>:%EC%Ey<U5E74>";/
+- "+:2:1912//07//30:1912//12//31:<U5927><U6B63>:%EC<U5143><U5E74>";/
++ "+:1:1912//07//30:1912//12//31:<U5927><U6B63>:%EC<U5143><U5E74>";/
+ "+:6:1873//01//01:1912//07//29:<U660E><U6CBB>:%EC%Ey<U5E74>";/
+ "+:1:0001//01//01:1872//12//31:<U897F><U66A6>:%EC%Ey<U5E74>";/
+ "+:1:-0001//12//31:-*:<U7D00><U5143><U524D>:%EC%Ey<U5E74>"
+diff --git a/malloc/malloc.c b/malloc/malloc.c
+index feaf7ee0bf..0abd653be2 100644
+--- a/malloc/malloc.c
++++ b/malloc/malloc.c
+@@ -2919,6 +2919,8 @@ typedef struct tcache_perthread_struct
+ tcache_entry *entries[TCACHE_MAX_BINS];
+ } tcache_perthread_struct;
+
++#define MAX_TCACHE_COUNT 127 /* Maximum value of counts[] entries. */
++
+ static __thread bool tcache_shutting_down = false;
+ static __thread tcache_perthread_struct *tcache = NULL;
+
+@@ -3876,10 +3878,14 @@ _int_malloc (mstate av, size_t bytes)
+ {
+ victim->fd_nextsize = fwd;
+ victim->bk_nextsize = fwd->bk_nextsize;
++ if (__glibc_unlikely (fwd->bk_nextsize->fd_nextsize != fwd))
++ malloc_printerr ("malloc(): largebin double linked list corrupted (nextsize)");
+ fwd->bk_nextsize = victim;
+ victim->bk_nextsize->fd_nextsize = victim;
+ }
+ bck = fwd->bk;
++ if (bck->fd != fwd)
++ malloc_printerr ("malloc(): largebin double linked list corrupted (bk)");
+ }
+ }
+ else
+@@ -5120,8 +5126,11 @@ static inline int
+ __always_inline
+ do_set_tcache_count (size_t value)
+ {
+- LIBC_PROBE (memory_tunable_tcache_count, 2, value, mp_.tcache_count);
+- mp_.tcache_count = value;
++ if (value <= MAX_TCACHE_COUNT)
++ {
++ LIBC_PROBE (memory_tunable_tcache_count, 2, value, mp_.tcache_count);
++ mp_.tcache_count = value;
++ }
+ return 1;
+ }
+
+diff --git a/malloc/mtrace.c b/malloc/mtrace.c
+index a2facf65ea..2fda262508 100644
+--- a/malloc/mtrace.c
++++ b/malloc/mtrace.c
+@@ -121,6 +121,41 @@ lock_and_info (const void *caller, Dl_info *mem)
+ return res;
+ }
+
++static void tr_freehook (void *, const void *);
++static void * tr_mallochook (size_t, const void *);
++static void * tr_reallochook (void *, size_t, const void *);
++static void * tr_memalignhook (size_t, size_t, const void *);
++
++/* Set all the default non-trace hooks. */
++static __always_inline void
++set_default_hooks (void)
++{
++ __free_hook = tr_old_free_hook;
++ __malloc_hook = tr_old_malloc_hook;
++ __realloc_hook = tr_old_realloc_hook;
++ __memalign_hook = tr_old_memalign_hook;
++}
++
++/* Set all of the tracing hooks used for mtrace. */
++static __always_inline void
++set_trace_hooks (void)
++{
++ __free_hook = tr_freehook;
++ __malloc_hook = tr_mallochook;
++ __realloc_hook = tr_reallochook;
++ __memalign_hook = tr_memalignhook;
++}
++
++/* Save the current set of hooks as the default hooks. */
++static __always_inline void
++save_default_hooks (void)
++{
++ tr_old_free_hook = __free_hook;
++ tr_old_malloc_hook = __malloc_hook;
++ tr_old_realloc_hook = __realloc_hook;
++ tr_old_memalign_hook = __memalign_hook;
++}
++
+ static void
+ tr_freehook (void *ptr, const void *caller)
+ {
+@@ -138,12 +173,12 @@ tr_freehook (void *ptr, const void *caller)
+ tr_break ();
+ __libc_lock_lock (lock);
+ }
+- __free_hook = tr_old_free_hook;
++ set_default_hooks ();
+ if (tr_old_free_hook != NULL)
+ (*tr_old_free_hook)(ptr, caller);
+ else
+ free (ptr);
+- __free_hook = tr_freehook;
++ set_trace_hooks ();
+ __libc_lock_unlock (lock);
+ }
+
+@@ -155,12 +190,12 @@ tr_mallochook (size_t size, const void *caller)
+ Dl_info mem;
+ Dl_info *info = lock_and_info (caller, &mem);
+
+- __malloc_hook = tr_old_malloc_hook;
++ set_default_hooks ();
+ if (tr_old_malloc_hook != NULL)
+ hdr = (void *) (*tr_old_malloc_hook)(size, caller);
+ else
+ hdr = (void *) malloc (size);
+- __malloc_hook = tr_mallochook;
++ set_trace_hooks ();
+
+ tr_where (caller, info);
+ /* We could be printing a NULL here; that's OK. */
+@@ -185,16 +220,12 @@ tr_reallochook (void *ptr, size_t size, const void *caller)
+ Dl_info mem;
+ Dl_info *info = lock_and_info (caller, &mem);
+
+- __free_hook = tr_old_free_hook;
+- __malloc_hook = tr_old_malloc_hook;
+- __realloc_hook = tr_old_realloc_hook;
++ set_default_hooks ();
+ if (tr_old_realloc_hook != NULL)
+ hdr = (void *) (*tr_old_realloc_hook)(ptr, size, caller);
+ else
+ hdr = (void *) realloc (ptr, size);
+- __free_hook = tr_freehook;
+- __malloc_hook = tr_mallochook;
+- __realloc_hook = tr_reallochook;
++ set_trace_hooks ();
+
+ tr_where (caller, info);
+ if (hdr == NULL)
+@@ -230,14 +261,12 @@ tr_memalignhook (size_t alignment, size_t size, const void *caller)
+ Dl_info mem;
+ Dl_info *info = lock_and_info (caller, &mem);
+
+- __memalign_hook = tr_old_memalign_hook;
+- __malloc_hook = tr_old_malloc_hook;
++ set_default_hooks ();
+ if (tr_old_memalign_hook != NULL)
+ hdr = (void *) (*tr_old_memalign_hook)(alignment, size, caller);
+ else
+ hdr = (void *) memalign (alignment, size);
+- __memalign_hook = tr_memalignhook;
+- __malloc_hook = tr_mallochook;
++ set_trace_hooks ();
+
+ tr_where (caller, info);
+ /* We could be printing a NULL here; that's OK. */
+@@ -305,14 +334,8 @@ mtrace (void)
+ malloc_trace_buffer = mtb;
+ setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE);
+ fprintf (mallstream, "= Start\n");
+- tr_old_free_hook = __free_hook;
+- __free_hook = tr_freehook;
+- tr_old_malloc_hook = __malloc_hook;
+- __malloc_hook = tr_mallochook;
+- tr_old_realloc_hook = __realloc_hook;
+- __realloc_hook = tr_reallochook;
+- tr_old_memalign_hook = __memalign_hook;
+- __memalign_hook = tr_memalignhook;
++ save_default_hooks ();
++ set_trace_hooks ();
+ #ifdef _LIBC
+ if (!added_atexit_handler)
+ {
+@@ -338,10 +361,7 @@ muntrace (void)
+ file. */
+ FILE *f = mallstream;
+ mallstream = NULL;
+- __free_hook = tr_old_free_hook;
+- __malloc_hook = tr_old_malloc_hook;
+- __realloc_hook = tr_old_realloc_hook;
+- __memalign_hook = tr_old_memalign_hook;
++ set_default_hooks ();
+
+ fprintf (f, "= End\n");
+ fclose (f);
+diff --git a/malloc/tst-malloc-too-large.c b/malloc/tst-malloc-too-large.c
+index 15e25f558e..51d42cee81 100644
+--- a/malloc/tst-malloc-too-large.c
++++ b/malloc/tst-malloc-too-large.c
+@@ -72,13 +72,28 @@ test_large_allocations (size_t size)
+ void * ptr_to_realloc;
+
+ test_setup ();
++ DIAG_PUSH_NEEDS_COMMENT;
++#if __GNUC_PREREQ (7, 0)
++ /* GCC 7 warns about too-large allocations; here we want to test
++ that they fail. */
++ DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than=");
++#endif
+ TEST_VERIFY (malloc (size) == NULL);
++#if __GNUC_PREREQ (7, 0)
++ DIAG_POP_NEEDS_COMMENT;
++#endif
+ TEST_VERIFY (errno == ENOMEM);
+
+ ptr_to_realloc = malloc (16);
+ TEST_VERIFY_EXIT (ptr_to_realloc != NULL);
+ test_setup ();
++#if __GNUC_PREREQ (7, 0)
++ DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than=");
++#endif
+ TEST_VERIFY (realloc (ptr_to_realloc, size) == NULL);
++#if __GNUC_PREREQ (7, 0)
++ DIAG_POP_NEEDS_COMMENT;
++#endif
+ TEST_VERIFY (errno == ENOMEM);
+ free (ptr_to_realloc);
+
+@@ -135,7 +150,13 @@ test_large_aligned_allocations (size_t size)
+ for (align = 1; align <= pagesize; align *= 2)
+ {
+ test_setup ();
++#if __GNUC_PREREQ (7, 0)
++ DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than=");
++#endif
+ TEST_VERIFY (memalign (align, size) == NULL);
++#if __GNUC_PREREQ (7, 0)
++ DIAG_POP_NEEDS_COMMENT;
++#endif
+ TEST_VERIFY (errno == ENOMEM);
+
+ /* posix_memalign expects an alignment that is a power of 2 *and* a
+@@ -151,7 +172,13 @@ test_large_aligned_allocations (size_t size)
+ if ((size % align) == 0)
+ {
+ test_setup ();
++#if __GNUC_PREREQ (7, 0)
++ DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than=");
++#endif
+ TEST_VERIFY (aligned_alloc (align, size) == NULL);
++#if __GNUC_PREREQ (7, 0)
++ DIAG_POP_NEEDS_COMMENT;
++#endif
+ TEST_VERIFY (errno == ENOMEM);
+ }
+ }
+@@ -159,11 +186,23 @@ test_large_aligned_allocations (size_t size)
+ /* Both valloc and pvalloc return page-aligned memory. */
+
+ test_setup ();
++#if __GNUC_PREREQ (7, 0)
++ DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than=");
++#endif
+ TEST_VERIFY (valloc (size) == NULL);
++#if __GNUC_PREREQ (7, 0)
++ DIAG_POP_NEEDS_COMMENT;
++#endif
+ TEST_VERIFY (errno == ENOMEM);
+
+ test_setup ();
++#if __GNUC_PREREQ (7, 0)
++ DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than=");
++#endif
+ TEST_VERIFY (pvalloc (size) == NULL);
++#if __GNUC_PREREQ (7, 0)
++ DIAG_POP_NEEDS_COMMENT;
++#endif
+ TEST_VERIFY (errno == ENOMEM);
+ }
+
+diff --git a/malloc/tst-memalign.c b/malloc/tst-memalign.c
+index a6a9140a3d..e7997518cb 100644
+--- a/malloc/tst-memalign.c
++++ b/malloc/tst-memalign.c
+@@ -21,6 +21,7 @@
+ #include <stdio.h>
+ #include <string.h>
+ #include <unistd.h>
++#include <libc-diag.h>
+
+ static int errors = 0;
+
+@@ -41,9 +42,18 @@ do_test (void)
+
+ errno = 0;
+
++ DIAG_PUSH_NEEDS_COMMENT;
++#if __GNUC_PREREQ (7, 0)
++ /* GCC 7 warns about too-large allocations; here we want to test
++ that they fail. */
++ DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than=");
++#endif
+ /* An attempt to allocate a huge value should return NULL and set
+ errno to ENOMEM. */
+ p = memalign (sizeof (void *), -1);
++#if __GNUC_PREREQ (7, 0)
++ DIAG_POP_NEEDS_COMMENT;
++#endif
+
+ save = errno;
+
+diff --git a/manual/tunables.texi b/manual/tunables.texi
+index af820820e0..8edfea4edd 100644
+--- a/manual/tunables.texi
++++ b/manual/tunables.texi
+@@ -189,8 +189,8 @@ per-thread cache. The default (and maximum) value is 1032 bytes on
+
+ @deftp Tunable glibc.malloc.tcache_count
+ The maximum number of chunks of each size to cache. The default is 7.
+-There is no upper limit, other than available system memory. If set
+-to zero, the per-thread cache is effectively disabled.
++The upper limit is 127. If set to zero, the per-thread cache is effectively
++disabled.
+
+ The approximate maximum overhead of the per-thread cache is thus equal
+ to the number of bins times the chunk count in each bin times the size
+diff --git a/nptl/Makefile b/nptl/Makefile
+index 340282c6cb..0e316edfac 100644
+--- a/nptl/Makefile
++++ b/nptl/Makefile
+@@ -319,7 +319,8 @@ tests = tst-attr1 tst-attr2 tst-attr3 tst-default-attr \
+ tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \
+ tst-cnd-timedwait tst-thrd-detach tst-mtx-basic tst-thrd-sleep \
+ tst-mtx-recursive tst-tss-basic tst-call-once tst-mtx-timedlock \
+- tst-rwlock-pwn
++ tst-rwlock-pwn \
++ tst-rwlock-tryrdlock-stall tst-rwlock-trywrlock-stall
+
+ tests-internal := tst-rwlock19 tst-rwlock20 \
+ tst-sem11 tst-sem12 tst-sem13 \
+diff --git a/nptl/pthread_join_common.c b/nptl/pthread_join_common.c
+index ecb78ffba5..366feb376b 100644
+--- a/nptl/pthread_join_common.c
++++ b/nptl/pthread_join_common.c
+@@ -86,6 +86,7 @@ __pthread_timedjoin_ex (pthread_t threadid, void **thread_return,
+ pthread_cleanup_pop (0);
+ }
+
++ void *pd_result = pd->result;
+ if (__glibc_likely (result == 0))
+ {
+ /* We mark the thread as terminated and as joined. */
+@@ -93,7 +94,7 @@ __pthread_timedjoin_ex (pthread_t threadid, void **thread_return,
+
+ /* Store the return value if the caller is interested. */
+ if (thread_return != NULL)
+- *thread_return = pd->result;
++ *thread_return = pd_result;
+
+ /* Free the TCB. */
+ __free_tcb (pd);
+@@ -101,7 +102,7 @@ __pthread_timedjoin_ex (pthread_t threadid, void **thread_return,
+ else
+ pd->joinid = NULL;
+
+- LIBC_PROBE (pthread_join_ret, 3, threadid, result, pd->result);
++ LIBC_PROBE (pthread_join_ret, 3, threadid, result, pd_result);
+
+ return result;
+ }
+diff --git a/nptl/pthread_mutex_trylock.c b/nptl/pthread_mutex_trylock.c
+index 8fe43b8f0f..bf2869eca2 100644
+--- a/nptl/pthread_mutex_trylock.c
++++ b/nptl/pthread_mutex_trylock.c
+@@ -94,6 +94,9 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
+ case PTHREAD_MUTEX_ROBUST_ADAPTIVE_NP:
+ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
+ &mutex->__data.__list.__next);
++ /* We need to set op_pending before starting the operation. Also
++ see comments at ENQUEUE_MUTEX. */
++ __asm ("" ::: "memory");
+
+ oldval = mutex->__data.__lock;
+ do
+@@ -119,7 +122,12 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
+ /* But it is inconsistent unless marked otherwise. */
+ mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT;
+
++ /* We must not enqueue the mutex before we have acquired it.
++ Also see comments at ENQUEUE_MUTEX. */
++ __asm ("" ::: "memory");
+ ENQUEUE_MUTEX (mutex);
++ /* We need to clear op_pending after we enqueue the mutex. */
++ __asm ("" ::: "memory");
+ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+
+ /* Note that we deliberately exist here. If we fall
+@@ -135,6 +143,8 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
+ int kind = PTHREAD_MUTEX_TYPE (mutex);
+ if (kind == PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP)
+ {
++ /* We do not need to ensure ordering wrt another memory
++ access. Also see comments at ENQUEUE_MUTEX. */
+ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
+ NULL);
+ return EDEADLK;
+@@ -142,6 +152,8 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
+
+ if (kind == PTHREAD_MUTEX_ROBUST_RECURSIVE_NP)
+ {
++ /* We do not need to ensure ordering wrt another memory
++ access. */
+ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
+ NULL);
+
+@@ -160,6 +172,9 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
+ id, 0);
+ if (oldval != 0 && (oldval & FUTEX_OWNER_DIED) == 0)
+ {
++ /* We haven't acquired the lock as it is already acquired by
++ another owner. We do not need to ensure ordering wrt another
++ memory access. */
+ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+
+ return EBUSY;
+@@ -173,13 +188,20 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
+ if (oldval == id)
+ lll_unlock (mutex->__data.__lock,
+ PTHREAD_ROBUST_MUTEX_PSHARED (mutex));
++ /* FIXME This violates the mutex destruction requirements. See
++ __pthread_mutex_unlock_full. */
+ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+ return ENOTRECOVERABLE;
+ }
+ }
+ while ((oldval & FUTEX_OWNER_DIED) != 0);
+
++ /* We must not enqueue the mutex before we have acquired it.
++ Also see comments at ENQUEUE_MUTEX. */
++ __asm ("" ::: "memory");
+ ENQUEUE_MUTEX (mutex);
++ /* We need to clear op_pending after we enqueue the mutex. */
++ __asm ("" ::: "memory");
+ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+
+ mutex->__data.__owner = id;
+@@ -211,10 +233,15 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
+ }
+
+ if (robust)
+- /* Note: robust PI futexes are signaled by setting bit 0. */
+- THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
+- (void *) (((uintptr_t) &mutex->__data.__list.__next)
+- | 1));
++ {
++ /* Note: robust PI futexes are signaled by setting bit 0. */
++ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
++ (void *) (((uintptr_t) &mutex->__data.__list.__next)
++ | 1));
++ /* We need to set op_pending before starting the operation. Also
++ see comments at ENQUEUE_MUTEX. */
++ __asm ("" ::: "memory");
++ }
+
+ oldval = mutex->__data.__lock;
+
+@@ -223,12 +250,16 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
+ {
+ if (kind == PTHREAD_MUTEX_ERRORCHECK_NP)
+ {
++ /* We do not need to ensure ordering wrt another memory
++ access. */
+ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+ return EDEADLK;
+ }
+
+ if (kind == PTHREAD_MUTEX_RECURSIVE_NP)
+ {
++ /* We do not need to ensure ordering wrt another memory
++ access. */
+ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+
+ /* Just bump the counter. */
+@@ -250,6 +281,9 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
+ {
+ if ((oldval & FUTEX_OWNER_DIED) == 0)
+ {
++ /* We haven't acquired the lock as it is already acquired by
++ another owner. We do not need to ensure ordering wrt another
++ memory access. */
+ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+
+ return EBUSY;
+@@ -270,6 +304,9 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
+ if (INTERNAL_SYSCALL_ERROR_P (e, __err)
+ && INTERNAL_SYSCALL_ERRNO (e, __err) == EWOULDBLOCK)
+ {
++ /* The kernel has not yet finished the mutex owner death.
++ We do not need to ensure ordering wrt another memory
++ access. */
+ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+
+ return EBUSY;
+@@ -287,7 +324,12 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
+ /* But it is inconsistent unless marked otherwise. */
+ mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT;
+
++ /* We must not enqueue the mutex before we have acquired it.
++ Also see comments at ENQUEUE_MUTEX. */
++ __asm ("" ::: "memory");
+ ENQUEUE_MUTEX (mutex);
++ /* We need to clear op_pending after we enqueue the mutex. */
++ __asm ("" ::: "memory");
+ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+
+ /* Note that we deliberately exit here. If we fall
+@@ -310,13 +352,20 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
+ PTHREAD_ROBUST_MUTEX_PSHARED (mutex)),
+ 0, 0);
+
++ /* To the kernel, this will be visible after the kernel has
++ acquired the mutex in the syscall. */
+ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+ return ENOTRECOVERABLE;
+ }
+
+ if (robust)
+ {
++ /* We must not enqueue the mutex before we have acquired it.
++ Also see comments at ENQUEUE_MUTEX. */
++ __asm ("" ::: "memory");
+ ENQUEUE_MUTEX_PI (mutex);
++ /* We need to clear op_pending after we enqueue the mutex. */
++ __asm ("" ::: "memory");
+ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
+ }
+
+diff --git a/nptl/pthread_rwlock_tryrdlock.c b/nptl/pthread_rwlock_tryrdlock.c
+index 368862ff07..2f94f17f36 100644
+--- a/nptl/pthread_rwlock_tryrdlock.c
++++ b/nptl/pthread_rwlock_tryrdlock.c
+@@ -94,15 +94,22 @@ __pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock)
+ /* Same as in __pthread_rwlock_rdlock_full:
+ We started the read phase, so we are also responsible for
+ updating the write-phase futex. Relaxed MO is sufficient.
+- Note that there can be no other reader that we have to wake
+- because all other readers will see the read phase started by us
+- (or they will try to start it themselves); if a writer started
+- the read phase, we cannot have started it. Furthermore, we
+- cannot discard a PTHREAD_RWLOCK_FUTEX_USED flag because we will
+- overwrite the value set by the most recent writer (or the readers
+- before it in case of explicit hand-over) and we know that there
+- are no waiting readers. */
+- atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 0);
++ We have to do the same steps as a writer would when handing over the
++ read phase to use because other readers cannot distinguish between
++ us and the writer.
++ Note that __pthread_rwlock_tryrdlock callers will not have to be
++ woken up because they will either see the read phase started by us
++ or they will try to start it themselves; however, callers of
++ __pthread_rwlock_rdlock_full just increase the reader count and then
++ check what state the lock is in, so they cannot distinguish between
++ us and a writer that acquired and released the lock in the
++ meantime. */
++ if ((atomic_exchange_relaxed (&rwlock->__data.__wrphase_futex, 0)
++ & PTHREAD_RWLOCK_FUTEX_USED) != 0)
++ {
++ int private = __pthread_rwlock_get_private (rwlock);
++ futex_wake (&rwlock->__data.__wrphase_futex, INT_MAX, private);
++ }
+ }
+
+ return 0;
+diff --git a/nptl/pthread_rwlock_trywrlock.c b/nptl/pthread_rwlock_trywrlock.c
+index fd37a71ce4..fae475cc70 100644
+--- a/nptl/pthread_rwlock_trywrlock.c
++++ b/nptl/pthread_rwlock_trywrlock.c
+@@ -46,8 +46,15 @@ __pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock)
+ &rwlock->__data.__readers, &r,
+ r | PTHREAD_RWLOCK_WRPHASE | PTHREAD_RWLOCK_WRLOCKED))
+ {
++ /* We have become the primary writer and we cannot have shared
++ the PTHREAD_RWLOCK_FUTEX_USED flag with someone else, so we
++ can simply enable blocking (see full wrlock code). */
+ atomic_store_relaxed (&rwlock->__data.__writers_futex, 1);
+- atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 1);
++ /* If we started a write phase, we need to enable readers to
++ wait. If we did not, we must not change it because other threads
++ may have set the PTHREAD_RWLOCK_FUTEX_USED in the meantime. */
++ if ((r & PTHREAD_RWLOCK_WRPHASE) == 0)
++ atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 1);
+ atomic_store_relaxed (&rwlock->__data.__cur_writer,
+ THREAD_GETMEM (THREAD_SELF, tid));
+ return 0;
+diff --git a/nptl/register-atfork.c b/nptl/register-atfork.c
+index bc797b761a..80a1becb5f 100644
+--- a/nptl/register-atfork.c
++++ b/nptl/register-atfork.c
+@@ -107,13 +107,14 @@ __unregister_atfork (void *dso_handle)
+ }
+
+ void
+-__run_fork_handlers (enum __run_fork_handler_type who)
++__run_fork_handlers (enum __run_fork_handler_type who, _Bool do_locking)
+ {
+ struct fork_handler *runp;
+
+ if (who == atfork_run_prepare)
+ {
+- lll_lock (atfork_lock, LLL_PRIVATE);
++ if (do_locking)
++ lll_lock (atfork_lock, LLL_PRIVATE);
+ size_t sl = fork_handler_list_size (&fork_handlers);
+ for (size_t i = sl; i > 0; i--)
+ {
+@@ -133,7 +134,8 @@ __run_fork_handlers (enum __run_fork_handler_type who)
+ else if (who == atfork_run_parent && runp->parent_handler)
+ runp->parent_handler ();
+ }
+- lll_unlock (atfork_lock, LLL_PRIVATE);
++ if (do_locking)
++ lll_unlock (atfork_lock, LLL_PRIVATE);
+ }
+ }
+
+diff --git a/nptl/tst-rwlock-tryrdlock-stall.c b/nptl/tst-rwlock-tryrdlock-stall.c
+new file mode 100644
+index 0000000000..5e476da2b8
+--- /dev/null
++++ b/nptl/tst-rwlock-tryrdlock-stall.c
+@@ -0,0 +1,355 @@
++/* Bug 23844: Test for pthread_rwlock_tryrdlock stalls.
++ Copyright (C) 2019 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, see
++ <http://www.gnu.org/licenses/>. */
++
++/* For a full analysis see comment:
++ https://sourceware.org/bugzilla/show_bug.cgi?id=23844#c14
++
++ Provided here for reference:
++
++ --- Analysis of pthread_rwlock_tryrdlock() stall ---
++ A read lock begins to execute.
++
++ In __pthread_rwlock_rdlock_full:
++
++ We can attempt a read lock, but find that the lock is
++ in a write phase (PTHREAD_RWLOCK_WRPHASE, or WP-bit
++ is set), and the lock is held by a primary writer
++ (PTHREAD_RWLOCK_WRLOCKED is set). In this case we must
++ wait for explicit hand over from the writer to us or
++ one of the other waiters. The read lock threads are
++ about to execute:
++
++ 341 r = (atomic_fetch_add_acquire (&rwlock->__data.__readers,
++ 342 (1 << PTHREAD_RWLOCK_READER_SHIFT))
++ 343 + (1 << PTHREAD_RWLOCK_READER_SHIFT));
++
++ An unlock beings to execute.
++
++ Then in __pthread_rwlock_wrunlock:
++
++ 547 unsigned int r = atomic_load_relaxed (&rwlock->__data.__readers);
++ ...
++ 549 while (!atomic_compare_exchange_weak_release
++ 550 (&rwlock->__data.__readers, &r,
++ 551 ((r ^ PTHREAD_RWLOCK_WRLOCKED)
++ 552 ^ ((r >> PTHREAD_RWLOCK_READER_SHIFT) == 0 ? 0
++ 553 : PTHREAD_RWLOCK_WRPHASE))))
++ 554 {
++ ...
++ 556 }
++
++ We clear PTHREAD_RWLOCK_WRLOCKED, and if there are
++ no readers so we leave the lock in PTHRAD_RWLOCK_WRPHASE.
++
++ Back in the read lock.
++
++ The read lock adjusts __readres as above.
++
++ 383 while ((r & PTHREAD_RWLOCK_WRPHASE) != 0
++ 384 && (r & PTHREAD_RWLOCK_WRLOCKED) == 0)
++ 385 {
++ ...
++ 390 if (atomic_compare_exchange_weak_acquire (&rwlock->__data.__readers, &r,
++ 391 r ^ PTHREAD_RWLOCK_WRPHASE))
++ 392 {
++
++ And then attemps to start the read phase.
++
++ Assume there happens to be a tryrdlock at this point, noting
++ that PTHREAD_RWLOCK_WRLOCKED is clear, and PTHREAD_RWLOCK_WRPHASE
++ is 1. So the try lock attemps to start the read phase.
++
++ In __pthread_rwlock_tryrdlock:
++
++ 44 if ((r & PTHREAD_RWLOCK_WRPHASE) == 0)
++ 45 {
++ ...
++ 49 if (((r & PTHREAD_RWLOCK_WRLOCKED) != 0)
++ 50 && (rwlock->__data.__flags
++ 51 == PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP))
++ 52 return EBUSY;
++ 53 rnew = r + (1 << PTHREAD_RWLOCK_READER_SHIFT);
++ 54 }
++ ...
++ 89 while (!atomic_compare_exchange_weak_acquire (&rwlock->__data.__readers,
++ 90 &r, rnew));
++
++ And succeeds.
++
++ Back in the write unlock:
++
++ 557 if ((r >> PTHREAD_RWLOCK_READER_SHIFT) != 0)
++ 558 {
++ ...
++ 563 if ((atomic_exchange_relaxed (&rwlock->__data.__wrphase_futex, 0)
++ 564 & PTHREAD_RWLOCK_FUTEX_USED) != 0)
++ 565 futex_wake (&rwlock->__data.__wrphase_futex, INT_MAX, private);
++ 566 }
++
++ We note that PTHREAD_RWLOCK_FUTEX_USED is non-zero
++ and don't wake anyone. This is OK because we handed
++ over to the trylock. It will be the trylock's responsibility
++ to wake any waiters.
++
++ Back in the read lock:
++
++ The read lock fails to install PTHRAD_REWLOCK_WRPHASE as 0 because
++ the __readers value was adjusted by the trylock, and so it falls through
++ to waiting on the lock for explicit handover from either a new writer
++ or a new reader.
++
++ 448 int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex,
++ 449 1 | PTHREAD_RWLOCK_FUTEX_USED,
++ 450 abstime, private);
++
++ We use PTHREAD_RWLOCK_FUTEX_USED to indicate the futex
++ is in use.
++
++ At this point we have readers waiting on the read lock
++ to unlock. The wrlock is done. The trylock is finishing
++ the installation of the read phase.
++
++ 92 if ((r & PTHREAD_RWLOCK_WRPHASE) != 0)
++ 93 {
++ ...
++ 105 atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 0);
++ 106 }
++
++ The trylock does note that we were the one that
++ installed the read phase, but the comments are not
++ correct, the execution ordering above shows that
++ readers might indeed be waiting, and they are.
++
++ The atomic_store_relaxed throws away PTHREAD_RWLOCK_FUTEX_USED,
++ and the waiting reader is never worken becuase as noted
++ above it is conditional on the futex being used.
++
++ The solution is for the trylock thread to inspect
++ PTHREAD_RWLOCK_FUTEX_USED and wake the waiting readers.
++
++ --- Analysis of pthread_rwlock_trywrlock() stall ---
++
++ A write lock begins to execute, takes the write lock,
++ and then releases the lock...
++
++ In pthread_rwlock_wrunlock():
++
++ 547 unsigned int r = atomic_load_relaxed (&rwlock->__data.__readers);
++ ...
++ 549 while (!atomic_compare_exchange_weak_release
++ 550 (&rwlock->__data.__readers, &r,
++ 551 ((r ^ PTHREAD_RWLOCK_WRLOCKED)
++ 552 ^ ((r >> PTHREAD_RWLOCK_READER_SHIFT) == 0 ? 0
++ 553 : PTHREAD_RWLOCK_WRPHASE))))
++ 554 {
++ ...
++ 556 }
++
++ ... leaving it in the write phase with zero readers
++ (the case where we leave the write phase in place
++ during a write unlock).
++
++ A write trylock begins to execute.
++
++ In __pthread_rwlock_trywrlock:
++
++ 40 while (((r & PTHREAD_RWLOCK_WRLOCKED) == 0)
++ 41 && (((r >> PTHREAD_RWLOCK_READER_SHIFT) == 0)
++ 42 || (prefer_writer && ((r & PTHREAD_RWLOCK_WRPHASE) != 0))))
++ 43 {
++
++ The lock is not locked.
++
++ There are no readers.
++
++ 45 if (atomic_compare_exchange_weak_acquire (
++ 46 &rwlock->__data.__readers, &r,
++ 47 r | PTHREAD_RWLOCK_WRPHASE | PTHREAD_RWLOCK_WRLOCKED))
++
++ We atomically install the write phase and we take the
++ exclusive write lock.
++
++ 48 {
++ 49 atomic_store_relaxed (&rwlock->__data.__writers_futex, 1);
++
++ We get this far.
++
++ A reader lock begins to execute.
++
++ In pthread_rwlock_rdlock:
++
++ 437 for (;;)
++ 438 {
++ 439 while (((wpf = atomic_load_relaxed (&rwlock->__data.__wrphase_futex))
++ 440 | PTHREAD_RWLOCK_FUTEX_USED) == (1 | PTHREAD_RWLOCK_FUTEX_USED))
++ 441 {
++ 442 int private = __pthread_rwlock_get_private (rwlock);
++ 443 if (((wpf & PTHREAD_RWLOCK_FUTEX_USED) == 0)
++ 444 && (!atomic_compare_exchange_weak_relaxed
++ 445 (&rwlock->__data.__wrphase_futex,
++ 446 &wpf, wpf | PTHREAD_RWLOCK_FUTEX_USED)))
++ 447 continue;
++ 448 int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex,
++ 449 1 | PTHREAD_RWLOCK_FUTEX_USED,
++ 450 abstime, private);
++
++ We are in a write phase, so the while() on line 439 is true.
++
++ The value of wpf does not have PTHREAD_RWLOCK_FUTEX_USED set
++ since this is the first reader to lock.
++
++ The atomic operation sets wpf with PTHREAD_RELOCK_FUTEX_USED
++ on the expectation that this reader will be woken during
++ the handoff.
++
++ Back in pthread_rwlock_trywrlock:
++
++ 50 atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 1);
++ 51 atomic_store_relaxed (&rwlock->__data.__cur_writer,
++ 52 THREAD_GETMEM (THREAD_SELF, tid));
++ 53 return 0;
++ 54 }
++ ...
++ 57 }
++
++ We write 1 to __wrphase_futex discarding PTHREAD_RWLOCK_FUTEX_USED,
++ and so in the unlock we will not awaken the waiting reader.
++
++ The solution to this is to realize that if we did not start the write
++ phase we need not write 1 or any other value to __wrphase_futex.
++ This ensures that any readers (which saw __wrphase_futex != 0) can
++ set PTHREAD_RWLOCK_FUTEX_USED and this can be used at unlock to
++ wake them.
++
++ If we installed the write phase then all other readers are looping
++ here:
++
++ In __pthread_rwlock_rdlock_full:
++
++ 437 for (;;)
++ 438 {
++ 439 while (((wpf = atomic_load_relaxed (&rwlock->__data.__wrphase_futex))
++ 440 | PTHREAD_RWLOCK_FUTEX_USED) == (1 | PTHREAD_RWLOCK_FUTEX_USED))
++ 441 {
++ ...
++ 508 }
++
++ waiting for the write phase to be installed or removed before they
++ can begin waiting on __wrphase_futex (part of the algorithm), or
++ taking a concurrent read lock, and thus we can safely write 1 to
++ __wrphase_futex.
++
++ If we did not install the write phase then the readers may already
++ be waiting on the futex, the original writer wrote 1 to __wrphase_futex
++ as part of starting the write phase, and we cannot also write 1
++ without loosing the PTHREAD_RWLOCK_FUTEX_USED bit.
++
++ ---
++
++ Summary for the pthread_rwlock_tryrdlock() stall:
++
++ The stall is caused by pthread_rwlock_tryrdlock failing to check
++ that PTHREAD_RWLOCK_FUTEX_USED is set in the __wrphase_futex futex
++ and then waking the futex.
++
++ The fix for bug 23844 ensures that waiters on __wrphase_futex are
++ correctly woken. Before the fix the test stalls as readers can
++ wait forever on __wrphase_futex. */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <pthread.h>
++#include <support/xthread.h>
++#include <errno.h>
++
++/* We need only one lock to reproduce the issue. We will need multiple
++ threads to get the exact case where we have a read, try, and unlock
++ all interleaving to produce the case where the readers are waiting
++ and the try fails to wake them. */
++pthread_rwlock_t onelock;
++
++/* The number of threads is arbitrary but empirically chosen to have
++ enough threads that we see the condition where waiting readers are
++ not woken by a successful tryrdlock. */
++#define NTHREADS 32
++
++_Atomic int do_exit;
++
++void *
++run_loop (void *arg)
++{
++ int i = 0, ret;
++ while (!do_exit)
++ {
++ /* Arbitrarily choose if we are the writer or reader. Choose a
++ high enough ratio of readers to writers to make it likely
++ that readers block (and eventually are susceptable to
++ stalling).
++
++ If we are a writer, take the write lock, and then unlock.
++ If we are a reader, try the lock, then lock, then unlock. */
++ if ((i % 8) != 0)
++ xpthread_rwlock_wrlock (&onelock);
++ else
++ {
++ if ((ret = pthread_rwlock_tryrdlock (&onelock)) != 0)
++ {
++ if (ret == EBUSY)
++ xpthread_rwlock_rdlock (&onelock);
++ else
++ exit (EXIT_FAILURE);
++ }
++ }
++ /* Thread does some work and then unlocks. */
++ xpthread_rwlock_unlock (&onelock);
++ i++;
++ }
++ return NULL;
++}
++
++int
++do_test (void)
++{
++ int i;
++ pthread_t tids[NTHREADS];
++ xpthread_rwlock_init (&onelock, NULL);
++ for (i = 0; i < NTHREADS; i++)
++ tids[i] = xpthread_create (NULL, run_loop, NULL);
++ /* Run for some amount of time. Empirically speaking exercising
++ the stall via pthread_rwlock_tryrdlock is much harder, and on
++ a 3.5GHz 4 core x86_64 VM system it takes somewhere around
++ 20-200s to stall, approaching 100% stall past 200s. We can't
++ wait that long for a regression test so we just test for 20s,
++ and expect the stall to happen with a 5-10% chance (enough for
++ developers to see). */
++ sleep (20);
++ /* Then exit. */
++ printf ("INFO: Exiting...\n");
++ do_exit = 1;
++ /* If any readers stalled then we will timeout waiting for them. */
++ for (i = 0; i < NTHREADS; i++)
++ xpthread_join (tids[i]);
++ printf ("INFO: Done.\n");
++ xpthread_rwlock_destroy (&onelock);
++ printf ("PASS: No pthread_rwlock_tryrdlock stalls detected.\n");
++ return 0;
++}
++
++#define TIMEOUT 30
++#include <support/test-driver.c>
+diff --git a/nptl/tst-rwlock-trywrlock-stall.c b/nptl/tst-rwlock-trywrlock-stall.c
+new file mode 100644
+index 0000000000..14d27cbcbc
+--- /dev/null
++++ b/nptl/tst-rwlock-trywrlock-stall.c
+@@ -0,0 +1,108 @@
++/* Bug 23844: Test for pthread_rwlock_trywrlock stalls.
++ Copyright (C) 2019 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, see
++ <http://www.gnu.org/licenses/>. */
++
++/* For a full analysis see comments in tst-rwlock-tryrdlock-stall.c.
++
++ Summary for the pthread_rwlock_trywrlock() stall:
++
++ The stall is caused by pthread_rwlock_trywrlock setting
++ __wrphase_futex futex to 1 and loosing the
++ PTHREAD_RWLOCK_FUTEX_USED bit.
++
++ The fix for bug 23844 ensures that waiters on __wrphase_futex are
++ correctly woken. Before the fix the test stalls as readers can
++ wait forever on __wrphase_futex. */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <pthread.h>
++#include <support/xthread.h>
++#include <errno.h>
++
++/* We need only one lock to reproduce the issue. We will need multiple
++ threads to get the exact case where we have a read, try, and unlock
++ all interleaving to produce the case where the readers are waiting
++ and the try clears the PTHREAD_RWLOCK_FUTEX_USED bit and a
++ subsequent unlock fails to wake them. */
++pthread_rwlock_t onelock;
++
++/* The number of threads is arbitrary but empirically chosen to have
++ enough threads that we see the condition where waiting readers are
++ not woken by a successful unlock. */
++#define NTHREADS 32
++
++_Atomic int do_exit;
++
++void *
++run_loop (void *arg)
++{
++ int i = 0, ret;
++ while (!do_exit)
++ {
++ /* Arbitrarily choose if we are the writer or reader. Choose a
++ high enough ratio of readers to writers to make it likely
++ that readers block (and eventually are susceptable to
++ stalling).
++
++ If we are a writer, take the write lock, and then unlock.
++ If we are a reader, try the lock, then lock, then unlock. */
++ if ((i % 8) != 0)
++ {
++ if ((ret = pthread_rwlock_trywrlock (&onelock)) != 0)
++ {
++ if (ret == EBUSY)
++ xpthread_rwlock_wrlock (&onelock);
++ else
++ exit (EXIT_FAILURE);
++ }
++ }
++ else
++ xpthread_rwlock_rdlock (&onelock);
++ /* Thread does some work and then unlocks. */
++ xpthread_rwlock_unlock (&onelock);
++ i++;
++ }
++ return NULL;
++}
++
++int
++do_test (void)
++{
++ int i;
++ pthread_t tids[NTHREADS];
++ xpthread_rwlock_init (&onelock, NULL);
++ for (i = 0; i < NTHREADS; i++)
++ tids[i] = xpthread_create (NULL, run_loop, NULL);
++ /* Run for some amount of time. The pthread_rwlock_tryrwlock stall
++ is very easy to trigger and happens in seconds under the test
++ conditions. */
++ sleep (10);
++ /* Then exit. */
++ printf ("INFO: Exiting...\n");
++ do_exit = 1;
++ /* If any readers stalled then we will timeout waiting for them. */
++ for (i = 0; i < NTHREADS; i++)
++ xpthread_join (tids[i]);
++ printf ("INFO: Done.\n");
++ xpthread_rwlock_destroy (&onelock);
++ printf ("PASS: No pthread_rwlock_tryrwlock stalls detected.\n");
++ return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/posix/bits/types.h b/posix/bits/types.h
+index 27e065c3be..0de6c59bb4 100644
+--- a/posix/bits/types.h
++++ b/posix/bits/types.h
+@@ -87,7 +87,7 @@ __extension__ typedef unsigned long long int __uintmax_t;
+ 32 -- "natural" 32-bit type (always int)
+ 64 -- "natural" 64-bit type (long or long long)
+ LONG32 -- 32-bit type, traditionally long
+- QUAD -- 64-bit type, always long long
++ QUAD -- 64-bit type, traditionally long long
+ WORD -- natural type of __WORDSIZE bits (int or long)
+ LONGWORD -- type of __WORDSIZE bits, traditionally long
+
+@@ -113,14 +113,14 @@ __extension__ typedef unsigned long long int __uintmax_t;
+ #define __SLONGWORD_TYPE long int
+ #define __ULONGWORD_TYPE unsigned long int
+ #if __WORDSIZE == 32
+-# define __SQUAD_TYPE __quad_t
+-# define __UQUAD_TYPE __u_quad_t
++# define __SQUAD_TYPE __int64_t
++# define __UQUAD_TYPE __uint64_t
+ # define __SWORD_TYPE int
+ # define __UWORD_TYPE unsigned int
+ # define __SLONG32_TYPE long int
+ # define __ULONG32_TYPE unsigned long int
+-# define __S64_TYPE __quad_t
+-# define __U64_TYPE __u_quad_t
++# define __S64_TYPE __int64_t
++# define __U64_TYPE __uint64_t
+ /* We want __extension__ before typedef's that use nonstandard base types
+ such as `long long' in C89 mode. */
+ # define __STD_TYPE __extension__ typedef
+diff --git a/posix/regexec.c b/posix/regexec.c
+index 91d5a797b8..084b1222d9 100644
+--- a/posix/regexec.c
++++ b/posix/regexec.c
+@@ -1293,8 +1293,10 @@ proceed_next_node (const re_match_context_t *mctx, Idx nregs, regmatch_t *regs,
+ else if (naccepted)
+ {
+ char *buf = (char *) re_string_get_buffer (&mctx->input);
+- if (memcmp (buf + regs[subexp_idx].rm_so, buf + *pidx,
+- naccepted) != 0)
++ if (mctx->input.valid_len - *pidx < naccepted
++ || (memcmp (buf + regs[subexp_idx].rm_so, buf + *pidx,
++ naccepted)
++ != 0))
+ return -1;
+ }
+ }
+diff --git a/posix/sys/types.h b/posix/sys/types.h
+index 27129c5c23..0e37b1ce6a 100644
+--- a/posix/sys/types.h
++++ b/posix/sys/types.h
+@@ -154,37 +154,20 @@ typedef unsigned int uint;
+
+ #include <bits/stdint-intn.h>
+
+-#if !__GNUC_PREREQ (2, 7)
+-
+ /* These were defined by ISO C without the first `_'. */
+-typedef unsigned char u_int8_t;
+-typedef unsigned short int u_int16_t;
+-typedef unsigned int u_int32_t;
+-# if __WORDSIZE == 64
+-typedef unsigned long int u_int64_t;
+-# else
+-__extension__ typedef unsigned long long int u_int64_t;
+-# endif
+-
+-typedef int register_t;
+-
+-#else
+-
+-/* For GCC 2.7 and later, we can use specific type-size attributes. */
+-# define __u_intN_t(N, MODE) \
+- typedef unsigned int u_int##N##_t __attribute__ ((__mode__ (MODE)))
+-
+-__u_intN_t (8, __QI__);
+-__u_intN_t (16, __HI__);
+-__u_intN_t (32, __SI__);
+-__u_intN_t (64, __DI__);
++typedef __uint8_t u_int8_t;
++typedef __uint16_t u_int16_t;
++typedef __uint32_t u_int32_t;
++typedef __uint64_t u_int64_t;
+
++#if __GNUC_PREREQ (2, 7)
+ typedef int register_t __attribute__ ((__mode__ (__word__)));
+-
++#else
++typedef int register_t;
++#endif
+
+ /* Some code from BIND tests this macro to see if the types above are
+ defined. */
+-#endif
+ #define __BIT_TYPES_DEFINED__ 1
+
+
+diff --git a/scripts/check-installed-headers.sh b/scripts/check-installed-headers.sh
+index 8e7beffd82..63bc8d4fa6 100644
+--- a/scripts/check-installed-headers.sh
++++ b/scripts/check-installed-headers.sh
+@@ -16,11 +16,9 @@
+ # License along with the GNU C Library; if not, see
+ # <http://www.gnu.org/licenses/>.
+
+-# Check installed headers for cleanliness. For each header, confirm
+-# that it's possible to compile a file that includes that header and
+-# does nothing else, in several different compilation modes. Also,
+-# scan the header for a set of obsolete typedefs that should no longer
+-# appear.
++# For each installed header, confirm that it's possible to compile a
++# file that includes that header and does nothing else, in several
++# different compilation modes.
+
+ # These compilation switches assume GCC or compatible, which is probably
+ # fine since we also assume that when _building_ glibc.
+@@ -31,13 +29,6 @@ cxx_modes="-std=c++98 -std=gnu++98 -std=c++11 -std=gnu++11"
+ # These are probably the most commonly used three.
+ lib_modes="-D_DEFAULT_SOURCE=1 -D_GNU_SOURCE=1 -D_XOPEN_SOURCE=700"
+
+-# sys/types.h+bits/types.h have to define the obsolete types.
+-# rpc(svc)/* have the obsolete types too deeply embedded in their API
+-# to remove.
+-skip_obsolete_type_check='*/sys/types.h|*/bits/types.h|*/rpc/*|*/rpcsvc/*'
+-obsolete_type_re=\
+-'\<((__)?(quad_t|u(short|int|long|_(char|short|int([0-9]+_t)?|long|quad_t))))\>'
+-
+ if [ $# -lt 3 ]; then
+ echo "usage: $0 c|c++ \"compile command\" header header header..." >&2
+ exit 2
+@@ -46,14 +37,10 @@ case "$1" in
+ (c)
+ lang_modes="$c_modes"
+ cih_test_c=$(mktemp ${TMPDIR-/tmp}/cih_test_XXXXXX.c)
+- already="$skip_obsolete_type_check"
+ ;;
+ (c++)
+ lang_modes="$cxx_modes"
+ cih_test_c=$(mktemp ${TMPDIR-/tmp}/cih_test_XXXXXX.cc)
+- # The obsolete-type check can be skipped for C++; it is
+- # sufficient to do it for C.
+- already="*"
+ ;;
+ (*)
+ echo "usage: $0 c|c++ \"compile command\" header header header..." >&2
+@@ -151,22 +138,8 @@ $expanded_lib_mode
+ int avoid_empty_translation_unit;
+ EOF
+ if $cc_cmd -fsyntax-only $lang_mode "$cih_test_c" 2>&1
+- then
+- includes=$($cc_cmd -fsyntax-only -H $lang_mode \
+- "$cih_test_c" 2>&1 | sed -ne 's/^[.][.]* //p')
+- for h in $includes; do
+- # Don't repeat work.
+- eval 'case "$h" in ('"$already"') continue;; esac'
+-
+- if grep -qE "$obsolete_type_re" "$h"; then
+- echo "*** Obsolete types detected:"
+- grep -HE "$obsolete_type_re" "$h"
+- failed=1
+- fi
+- already="$already|$h"
+- done
+- else
+- failed=1
++ then :
++ else failed=1
+ fi
+ done
+ done
+diff --git a/scripts/check-obsolete-constructs.py b/scripts/check-obsolete-constructs.py
+new file mode 100755
+index 0000000000..ce5c72251f
+--- /dev/null
++++ b/scripts/check-obsolete-constructs.py
+@@ -0,0 +1,466 @@
++#! /usr/bin/python3
++# Copyright (C) 2019 Free Software Foundation, Inc.
++# This file is part of the GNU C Library.
++#
++# The GNU C Library is free software; you can redistribute it and/or
++# modify it under the terms of the GNU Lesser General Public
++# License as published by the Free Software Foundation; either
++# version 2.1 of the License, or (at your option) any later version.
++#
++# The GNU C Library is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++# Lesser General Public License for more details.
++#
++# You should have received a copy of the GNU Lesser General Public
++# License along with the GNU C Library; if not, see
++# <http://www.gnu.org/licenses/>.
++
++"""Verifies that installed headers do not use any obsolete constructs:
++ * legacy BSD typedefs superseded by <stdint.h>:
++ ushort uint ulong u_char u_short u_int u_long u_intNN_t quad_t u_quad_t
++ (sys/types.h is allowed to _define_ these types, but not to use them
++ to define anything else).
++"""
++
++import argparse
++import collections
++import re
++import sys
++
++# Simplified lexical analyzer for C preprocessing tokens.
++# Does not implement trigraphs.
++# Does not implement backslash-newline in the middle of any lexical
++# item other than a string literal.
++# Does not implement universal-character-names in identifiers.
++# Treats prefixed strings (e.g. L"...") as two tokens (L and "...")
++# Accepts non-ASCII characters only within comments and strings.
++
++# Caution: The order of the outermost alternation matters.
++# STRING must be before BAD_STRING, CHARCONST before BAD_CHARCONST,
++# BLOCK_COMMENT before BAD_BLOCK_COM before PUNCTUATOR, and OTHER must
++# be last.
++# Caution: There should be no capturing groups other than the named
++# captures in the outermost alternation.
++
++# For reference, these are all of the C punctuators as of C11:
++# [ ] ( ) { } , ; ? ~
++# ! != * *= / /= ^ ^= = ==
++# # ##
++# % %= %> %: %:%:
++# & &= &&
++# | |= ||
++# + += ++
++# - -= -- ->
++# . ...
++# : :>
++# < <% <: << <<= <=
++# > >= >> >>=
++
++# The BAD_* tokens are not part of the official definition of pp-tokens;
++# they match unclosed strings, character constants, and block comments,
++# so that the regex engine doesn't have to backtrack all the way to the
++# beginning of a broken construct and then emit dozens of junk tokens.
++
++PP_TOKEN_RE_ = re.compile(r"""
++ (?P<STRING> \"(?:[^\"\\\r\n]|\\(?:[\r\n -~]|\r\n))*\")
++ |(?P<BAD_STRING> \"(?:[^\"\\\r\n]|\\[ -~])*)
++ |(?P<CHARCONST> \'(?:[^\'\\\r\n]|\\(?:[\r\n -~]|\r\n))*\')
++ |(?P<BAD_CHARCONST> \'(?:[^\'\\\r\n]|\\[ -~])*)
++ |(?P<BLOCK_COMMENT> /\*(?:\*(?!/)|[^*])*\*/)
++ |(?P<BAD_BLOCK_COM> /\*(?:\*(?!/)|[^*])*\*?)
++ |(?P<LINE_COMMENT> //[^\r\n]*)
++ |(?P<IDENT> [_a-zA-Z][_a-zA-Z0-9]*)
++ |(?P<PP_NUMBER> \.?[0-9](?:[0-9a-df-oq-zA-DF-OQ-Z_.]|[eEpP][+-]?)*)
++ |(?P<PUNCTUATOR>
++ [,;?~(){}\[\]]
++ | [!*/^=]=?
++ | \#\#?
++ | %(?:[=>]|:(?:%:)?)?
++ | &[=&]?
++ |\|[=|]?
++ |\+[=+]?
++ | -[=->]?
++ |\.(?:\.\.)?
++ | :>?
++ | <(?:[%:]|<(?:=|<=?)?)?
++ | >(?:=|>=?)?)
++ |(?P<ESCNL> \\(?:\r|\n|\r\n))
++ |(?P<WHITESPACE> [ \t\n\r\v\f]+)
++ |(?P<OTHER> .)
++""", re.DOTALL | re.VERBOSE)
++
++HEADER_NAME_RE_ = re.compile(r"""
++ < [^>\r\n]+ >
++ | " [^"\r\n]+ "
++""", re.DOTALL | re.VERBOSE)
++
++ENDLINE_RE_ = re.compile(r"""\r|\n|\r\n""")
++
++# based on the sample code in the Python re documentation
++Token_ = collections.namedtuple("Token", (
++ "kind", "text", "line", "column", "context"))
++Token_.__doc__ = """
++ One C preprocessing token, comment, or chunk of whitespace.
++ 'kind' identifies the token type, which will be one of:
++ STRING, CHARCONST, BLOCK_COMMENT, LINE_COMMENT, IDENT,
++ PP_NUMBER, PUNCTUATOR, ESCNL, WHITESPACE, HEADER_NAME,
++ or OTHER. The BAD_* alternatives in PP_TOKEN_RE_ are
++ handled within tokenize_c, below.
++
++ 'text' is the sequence of source characters making up the token;
++ no decoding whatsoever is performed.
++
++ 'line' and 'column' give the position of the first character of the
++ token within the source file. They are both 1-based.
++
++ 'context' indicates whether or not this token occurred within a
++ preprocessing directive; it will be None for running text,
++ '<null>' for the leading '#' of a directive line (because '#'
++ all by itself on a line is a "null directive"), or the name of
++ the directive for tokens within a directive line, starting with
++ the IDENT for the name itself.
++"""
++
++def tokenize_c(file_contents, reporter):
++ """Yield a series of Token objects, one for each preprocessing
++ token, comment, or chunk of whitespace within FILE_CONTENTS.
++ The REPORTER object is expected to have one method,
++ reporter.error(token, message), which will be called to
++ indicate a lexical error at the position of TOKEN.
++ If MESSAGE contains the four-character sequence '{!r}', that
++ is expected to be replaced by repr(token.text).
++ """
++
++ Token = Token_
++ PP_TOKEN_RE = PP_TOKEN_RE_
++ ENDLINE_RE = ENDLINE_RE_
++ HEADER_NAME_RE = HEADER_NAME_RE_
++
++ line_num = 1
++ line_start = 0
++ pos = 0
++ limit = len(file_contents)
++ directive = None
++ at_bol = True
++ while pos < limit:
++ if directive == "include":
++ mo = HEADER_NAME_RE.match(file_contents, pos)
++ if mo:
++ kind = "HEADER_NAME"
++ directive = "after_include"
++ else:
++ mo = PP_TOKEN_RE.match(file_contents, pos)
++ kind = mo.lastgroup
++ if kind != "WHITESPACE":
++ directive = "after_include"
++ else:
++ mo = PP_TOKEN_RE.match(file_contents, pos)
++ kind = mo.lastgroup
++
++ text = mo.group()
++ line = line_num
++ column = mo.start() - line_start
++ adj_line_start = 0
++ # only these kinds can contain a newline
++ if kind in ("WHITESPACE", "BLOCK_COMMENT", "LINE_COMMENT",
++ "STRING", "CHARCONST", "BAD_BLOCK_COM", "ESCNL"):
++ for tmo in ENDLINE_RE.finditer(text):
++ line_num += 1
++ adj_line_start = tmo.end()
++ if adj_line_start:
++ line_start = mo.start() + adj_line_start
++
++ # Track whether or not we are scanning a preprocessing directive.
++ if kind == "LINE_COMMENT" or (kind == "WHITESPACE" and adj_line_start):
++ at_bol = True
++ directive = None
++ else:
++ if kind == "PUNCTUATOR" and text == "#" and at_bol:
++ directive = "<null>"
++ elif kind == "IDENT" and directive == "<null>":
++ directive = text
++ at_bol = False
++
++ # Report ill-formed tokens and rewrite them as their well-formed
++ # equivalents, so downstream processing doesn't have to know about them.
++ # (Rewriting instead of discarding provides better error recovery.)
++ if kind == "BAD_BLOCK_COM":
++ reporter.error(Token("BAD_BLOCK_COM", "", line, column+1, ""),
++ "unclosed block comment")
++ text += "*/"
++ kind = "BLOCK_COMMENT"
++ elif kind == "BAD_STRING":
++ reporter.error(Token("BAD_STRING", "", line, column+1, ""),
++ "unclosed string")
++ text += "\""
++ kind = "STRING"
++ elif kind == "BAD_CHARCONST":
++ reporter.error(Token("BAD_CHARCONST", "", line, column+1, ""),
++ "unclosed char constant")
++ text += "'"
++ kind = "CHARCONST"
++
++ tok = Token(kind, text, line, column+1,
++ "include" if directive == "after_include" else directive)
++ # Do not complain about OTHER tokens inside macro definitions.
++ # $ and @ appear in macros defined by headers intended to be
++ # included from assembly language, e.g. sysdeps/mips/sys/asm.h.
++ if kind == "OTHER" and directive != "define":
++ self.error(tok, "stray {!r} in program")
++
++ yield tok
++ pos = mo.end()
++
++#
++# Base and generic classes for individual checks.
++#
++
++class ConstructChecker:
++ """Scan a stream of C preprocessing tokens and possibly report
++ problems with them. The REPORTER object passed to __init__ has
++ one method, reporter.error(token, message), which should be
++ called to indicate a problem detected at the position of TOKEN.
++ If MESSAGE contains the four-character sequence '{!r}' then that
++ will be replaced with a textual representation of TOKEN.
++ """
++ def __init__(self, reporter):
++ self.reporter = reporter
++
++ def examine(self, tok):
++ """Called once for each token in a header file.
++ Call self.reporter.error if a problem is detected.
++ """
++ raise NotImplementedError
++
++ def eof(self):
++ """Called once at the end of the stream. Subclasses need only
++ override this if it might have something to do."""
++ pass
++
++class NoCheck(ConstructChecker):
++ """Generic checker class which doesn't do anything. Substitute this
++ class for a real checker when a particular check should be skipped
++ for some file."""
++
++ def examine(self, tok):
++ pass
++
++#
++# Check for obsolete type names.
++#
++
++# The obsolete type names we're looking for:
++OBSOLETE_TYPE_RE_ = re.compile(r"""\A
++ (__)?
++ ( quad_t
++ | u(?: short | int | long
++ | _(?: char | short | int(?:[0-9]+_t)? | long | quad_t )))
++\Z""", re.VERBOSE)
++
++class ObsoleteNotAllowed(ConstructChecker):
++ """Don't allow any use of the obsolete typedefs."""
++ def examine(self, tok):
++ if OBSOLETE_TYPE_RE_.match(tok.text):
++ self.reporter.error(tok, "use of {!r}")
++
++class ObsoletePrivateDefinitionsAllowed(ConstructChecker):
++ """Allow definitions of the private versions of the
++ obsolete typedefs; that is, 'typedef [anything] __obsolete;'
++ """
++ def __init__(self, reporter):
++ super().__init__(reporter)
++ self.in_typedef = False
++ self.prev_token = None
++
++ def examine(self, tok):
++ # bits/types.h hides 'typedef' in a macro sometimes.
++ if (tok.kind == "IDENT"
++ and tok.text in ("typedef", "__STD_TYPE")
++ and tok.context is None):
++ self.in_typedef = True
++ elif tok.kind == "PUNCTUATOR" and tok.text == ";" and self.in_typedef:
++ self.in_typedef = False
++ if self.prev_token.kind == "IDENT":
++ m = OBSOLETE_TYPE_RE_.match(self.prev_token.text)
++ if m and m.group(1) != "__":
++ self.reporter.error(self.prev_token, "use of {!r}")
++ self.prev_token = None
++ else:
++ self._check_prev()
++
++ self.prev_token = tok
++
++ def eof(self):
++ self._check_prev()
++
++ def _check_prev(self):
++ if (self.prev_token is not None
++ and self.prev_token.kind == "IDENT"
++ and OBSOLETE_TYPE_RE_.match(self.prev_token.text)):
++ self.reporter.error(self.prev_token, "use of {!r}")
++
++class ObsoletePublicDefinitionsAllowed(ConstructChecker):
++ """Allow definitions of the public versions of the obsolete
++ typedefs. Only specific forms of definition are allowed:
++
++ typedef __obsolete obsolete; // identifiers must agree
++ typedef __uintN_t u_intN_t; // N must agree
++ typedef unsigned long int ulong;
++ typedef unsigned short int ushort;
++ typedef unsigned int uint;
++ """
++ def __init__(self, reporter):
++ super().__init__(reporter)
++ self.typedef_tokens = []
++
++ def examine(self, tok):
++ if tok.kind in ("WHITESPACE", "BLOCK_COMMENT",
++ "LINE_COMMENT", "NL", "ESCNL"):
++ pass
++
++ elif (tok.kind == "IDENT" and tok.text == "typedef"
++ and tok.context is None):
++ if self.typedef_tokens:
++ self.reporter.error(tok, "typedef inside typedef")
++ self._reset()
++ self.typedef_tokens.append(tok)
++
++ elif tok.kind == "PUNCTUATOR" and tok.text == ";":
++ self._finish()
++
++ elif self.typedef_tokens:
++ self.typedef_tokens.append(tok)
++
++ def eof(self):
++ self._reset()
++
++ def _reset(self):
++ while self.typedef_tokens:
++ tok = self.typedef_tokens.pop(0)
++ if tok.kind == "IDENT" and OBSOLETE_TYPE_RE_.match(tok.text):
++ self.reporter.error(tok, "use of {!r}")
++
++ def _finish(self):
++ if not self.typedef_tokens: return
++ if self.typedef_tokens[-1].kind == "IDENT":
++ m = OBSOLETE_TYPE_RE_.match(self.typedef_tokens[-1].text)
++ if m:
++ if self._permissible_public_definition(m):
++ self.typedef_tokens.clear()
++ self._reset()
++
++ def _permissible_public_definition(self, m):
++ if m.group(1) == "__": return False
++ name = m.group(2)
++ toks = self.typedef_tokens
++ ntok = len(toks)
++ if ntok == 3 and toks[1].kind == "IDENT":
++ defn = toks[1].text
++ n = OBSOLETE_TYPE_RE_.match(defn)
++ if n and n.group(1) == "__" and n.group(2) == name:
++ return True
++
++ if (name[:5] == "u_int" and name[-2:] == "_t"
++ and defn[:6] == "__uint" and defn[-2:] == "_t"
++ and name[5:-2] == defn[6:-2]):
++ return True
++
++ return False
++
++ if (name == "ulong" and ntok == 5
++ and toks[1].kind == "IDENT" and toks[1].text == "unsigned"
++ and toks[2].kind == "IDENT" and toks[2].text == "long"
++ and toks[3].kind == "IDENT" and toks[3].text == "int"):
++ return True
++
++ if (name == "ushort" and ntok == 5
++ and toks[1].kind == "IDENT" and toks[1].text == "unsigned"
++ and toks[2].kind == "IDENT" and toks[2].text == "short"
++ and toks[3].kind == "IDENT" and toks[3].text == "int"):
++ return True
++
++ if (name == "uint" and ntok == 4
++ and toks[1].kind == "IDENT" and toks[1].text == "unsigned"
++ and toks[2].kind == "IDENT" and toks[2].text == "int"):
++ return True
++
++ return False
++
++def ObsoleteTypedefChecker(reporter, fname):
++ """Factory: produce an instance of the appropriate
++ obsolete-typedef checker for FNAME."""
++
++ # The obsolete rpc/ and rpcsvc/ headers are allowed to use the
++ # obsolete types, because it would be more trouble than it's
++ # worth to remove them from headers that we intend to stop
++ # installing eventually anyway.
++ if (fname.startswith("rpc/")
++ or fname.startswith("rpcsvc/")
++ or "/rpc/" in fname
++ or "/rpcsvc/" in fname):
++ return NoCheck(reporter)
++
++ # bits/types.h is allowed to define the __-versions of the
++ # obsolete types.
++ if (fname == "bits/types.h"
++ or fname.endswith("/bits/types.h")):
++ return ObsoletePrivateDefinitionsAllowed(reporter)
++
++ # sys/types.h is allowed to use the __-versions of the
++ # obsolete types, but only to define the unprefixed versions.
++ if (fname == "sys/types.h"
++ or fname.endswith("/sys/types.h")):
++ return ObsoletePublicDefinitionsAllowed(reporter)
++
++ return ObsoleteNotAllowed(reporter)
++
++#
++# Master control
++#
++
++class HeaderChecker:
++ """Perform all of the checks on each header. This is also the
++ "reporter" object expected by tokenize_c and ConstructChecker.
++ """
++ def __init__(self):
++ self.fname = None
++ self.status = 0
++
++ def error(self, tok, message):
++ self.status = 1
++ if '{!r}' in message:
++ message = message.format(tok.text)
++ sys.stderr.write("{}:{}:{}: error: {}\n".format(
++ self.fname, tok.line, tok.column, message))
++
++ def check(self, fname):
++ self.fname = fname
++ try:
++ with open(fname, "rt") as fp:
++ contents = fp.read()
++ except OSError as e:
++ sys.stderr.write("{}: {}\n".format(fname, e.strerror))
++ self.status = 1
++ return
++
++ typedef_checker = ObsoleteTypedefChecker(self, self.fname)
++
++ for tok in tokenize_c(contents, self):
++ typedef_checker.examine(tok)
++
++def main():
++ ap = argparse.ArgumentParser(description=__doc__)
++ ap.add_argument("headers", metavar="header", nargs="+",
++ help="one or more headers to scan for obsolete constructs")
++ args = ap.parse_args()
++
++ checker = HeaderChecker()
++ for fname in args.headers:
++ # Headers whose installed name begins with "finclude/" contain
++ # Fortran, not C, and this program should completely ignore them.
++ if not (fname.startswith("finclude/") or "/finclude/" in fname):
++ checker.check(fname)
++ sys.exit(checker.status)
++
++main()
+diff --git a/support/Makefile b/support/Makefile
+index 432cf2fe6c..8d61de6c57 100644
+--- a/support/Makefile
++++ b/support/Makefile
+@@ -63,6 +63,7 @@ libsupport-routines = \
+ support_record_failure \
+ support_run_diff \
+ support_shared_allocate \
++ support_subprocess \
+ support_test_compare_blob \
+ support_test_compare_failure \
+ support_test_compare_string \
+@@ -129,6 +130,7 @@ libsupport-routines = \
+ xpthread_mutexattr_settype \
+ xpthread_once \
+ xpthread_rwlock_init \
++ xpthread_rwlock_destroy \
+ xpthread_rwlock_rdlock \
+ xpthread_rwlock_unlock \
+ xpthread_rwlock_wrlock \
+@@ -147,6 +149,9 @@ libsupport-routines = \
+ xsignal \
+ xsigstack \
+ xsocket \
++ xposix_spawn \
++ xposix_spawn_file_actions_addclose \
++ xposix_spawn_file_actions_adddup2 \
+ xstrdup \
+ xstrndup \
+ xsymlink \
+@@ -222,4 +227,6 @@ endif
+
+ $(objpfx)tst-support_format_dns_packet: $(common-objpfx)resolv/libresolv.so
+
++tst-support_capture_subprocess-ARGS = -- $(host-test-program-cmd)
++
+ include ../Rules
+diff --git a/support/capture_subprocess.h b/support/capture_subprocess.h
+index 2dce42e3a3..2832cfc635 100644
+--- a/support/capture_subprocess.h
++++ b/support/capture_subprocess.h
+@@ -35,6 +35,12 @@ struct support_capture_subprocess
+ struct support_capture_subprocess support_capture_subprocess
+ (void (*callback) (void *), void *closure);
+
++/* Issue FILE with ARGV arguments by using posix_spawn and capture standard
++ output, standard error, and the exit status. The out.buffer and err.buffer
++ are handle as support_capture_subprocess. */
++struct support_capture_subprocess support_capture_subprogram
++ (const char *file, char *const argv[]);
++
+ /* Deallocate the subprocess data captured by
+ support_capture_subprocess. */
+ void support_capture_subprocess_free (struct support_capture_subprocess *);
+diff --git a/support/subprocess.h b/support/subprocess.h
+new file mode 100644
+index 0000000000..c031878d94
+--- /dev/null
++++ b/support/subprocess.h
+@@ -0,0 +1,49 @@
++/* Create a subprocess.
++ Copyright (C) 2019 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, see
++ <http://www.gnu.org/licenses/>. */
++
++#ifndef SUPPORT_SUBPROCESS_H
++#define SUPPORT_SUBPROCESS_H
++
++#include <sys/types.h>
++
++struct support_subprocess
++{
++ int stdout_pipe[2];
++ int stderr_pipe[2];
++ pid_t pid;
++};
++
++/* Invoke CALLBACK (CLOSURE) in a subprocess created with fork and return
++ its PID, a pipe redirected to STDOUT, and a pipe redirected to STDERR. */
++struct support_subprocess support_subprocess
++ (void (*callback) (void *), void *closure);
++
++/* Issue FILE with ARGV arguments by using posix_spawn and return is PID, a
++ pipe redirected to STDOUT, and a pipe redirected to STDERR. */
++struct support_subprocess support_subprogram
++ (const char *file, char *const argv[]);
++
++/* Wait for the subprocess indicated by PROC::PID. Return the status
++ indicate by waitpid call. */
++int support_process_wait (struct support_subprocess *proc);
++
++/* Terminate the subprocess indicated by PROC::PID, first with a SIGTERM and
++ then with a SIGKILL. Return the status as for waitpid call. */
++int support_process_terminate (struct support_subprocess *proc);
++
++#endif
+diff --git a/support/support_capture_subprocess.c b/support/support_capture_subprocess.c
+index 167514faf1..948ce5a0c6 100644
+--- a/support/support_capture_subprocess.c
++++ b/support/support_capture_subprocess.c
+@@ -16,6 +16,7 @@
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
++#include <support/subprocess.h>
+ #include <support/capture_subprocess.h>
+
+ #include <errno.h>
+@@ -23,6 +24,7 @@
+ #include <support/check.h>
+ #include <support/xunistd.h>
+ #include <support/xsocket.h>
++#include <support/xspawn.h>
+
+ static void
+ transfer (const char *what, struct pollfd *pfd, struct xmemstream *stream)
+@@ -50,59 +52,53 @@ transfer (const char *what, struct pollfd *pfd, struct xmemstream *stream)
+ }
+ }
+
+-struct support_capture_subprocess
+-support_capture_subprocess (void (*callback) (void *), void *closure)
++static void
++support_capture_poll (struct support_capture_subprocess *result,
++ struct support_subprocess *proc)
+ {
+- struct support_capture_subprocess result;
+- xopen_memstream (&result.out);
+- xopen_memstream (&result.err);
+-
+- int stdout_pipe[2];
+- xpipe (stdout_pipe);
+- TEST_VERIFY (stdout_pipe[0] > STDERR_FILENO);
+- TEST_VERIFY (stdout_pipe[1] > STDERR_FILENO);
+- int stderr_pipe[2];
+- xpipe (stderr_pipe);
+- TEST_VERIFY (stderr_pipe[0] > STDERR_FILENO);
+- TEST_VERIFY (stderr_pipe[1] > STDERR_FILENO);
+-
+- TEST_VERIFY (fflush (stdout) == 0);
+- TEST_VERIFY (fflush (stderr) == 0);
+-
+- pid_t pid = xfork ();
+- if (pid == 0)
+- {
+- xclose (stdout_pipe[0]);
+- xclose (stderr_pipe[0]);
+- xdup2 (stdout_pipe[1], STDOUT_FILENO);
+- xdup2 (stderr_pipe[1], STDERR_FILENO);
+- xclose (stdout_pipe[1]);
+- xclose (stderr_pipe[1]);
+- callback (closure);
+- _exit (0);
+- }
+- xclose (stdout_pipe[1]);
+- xclose (stderr_pipe[1]);
+-
+ struct pollfd fds[2] =
+ {
+- { .fd = stdout_pipe[0], .events = POLLIN },
+- { .fd = stderr_pipe[0], .events = POLLIN },
++ { .fd = proc->stdout_pipe[0], .events = POLLIN },
++ { .fd = proc->stderr_pipe[0], .events = POLLIN },
+ };
+
+ do
+ {
+ xpoll (fds, 2, -1);
+- transfer ("stdout", &fds[0], &result.out);
+- transfer ("stderr", &fds[1], &result.err);
++ transfer ("stdout", &fds[0], &result->out);
++ transfer ("stderr", &fds[1], &result->err);
+ }
+ while (fds[0].events != 0 || fds[1].events != 0);
+- xclose (stdout_pipe[0]);
+- xclose (stderr_pipe[0]);
+
+- xfclose_memstream (&result.out);
+- xfclose_memstream (&result.err);
+- xwaitpid (pid, &result.status, 0);
++ xfclose_memstream (&result->out);
++ xfclose_memstream (&result->err);
++
++ result->status = support_process_wait (proc);
++}
++
++struct support_capture_subprocess
++support_capture_subprocess (void (*callback) (void *), void *closure)
++{
++ struct support_capture_subprocess result;
++ xopen_memstream (&result.out);
++ xopen_memstream (&result.err);
++
++ struct support_subprocess proc = support_subprocess (callback, closure);
++
++ support_capture_poll (&result, &proc);
++ return result;
++}
++
++struct support_capture_subprocess
++support_capture_subprogram (const char *file, char *const argv[])
++{
++ struct support_capture_subprocess result;
++ xopen_memstream (&result.out);
++ xopen_memstream (&result.err);
++
++ struct support_subprocess proc = support_subprogram (file, argv);
++
++ support_capture_poll (&result, &proc);
+ return result;
+ }
+
+diff --git a/support/support_subprocess.c b/support/support_subprocess.c
+new file mode 100644
+index 0000000000..0c8cc6af30
+--- /dev/null
++++ b/support/support_subprocess.c
+@@ -0,0 +1,152 @@
++/* Create subprocess.
++ Copyright (C) 2019 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, see
++ <http://www.gnu.org/licenses/>. */
++
++#include <stdio.h>
++#include <signal.h>
++#include <time.h>
++#include <sys/wait.h>
++#include <stdbool.h>
++#include <support/xspawn.h>
++#include <support/check.h>
++#include <support/xunistd.h>
++#include <support/subprocess.h>
++
++static struct support_subprocess
++support_suprocess_init (void)
++{
++ struct support_subprocess result;
++
++ xpipe (result.stdout_pipe);
++ TEST_VERIFY (result.stdout_pipe[0] > STDERR_FILENO);
++ TEST_VERIFY (result.stdout_pipe[1] > STDERR_FILENO);
++
++ xpipe (result.stderr_pipe);
++ TEST_VERIFY (result.stderr_pipe[0] > STDERR_FILENO);
++ TEST_VERIFY (result.stderr_pipe[1] > STDERR_FILENO);
++
++ TEST_VERIFY (fflush (stdout) == 0);
++ TEST_VERIFY (fflush (stderr) == 0);
++
++ return result;
++}
++
++struct support_subprocess
++support_subprocess (void (*callback) (void *), void *closure)
++{
++ struct support_subprocess result = support_suprocess_init ();
++
++ result.pid = xfork ();
++ if (result.pid == 0)
++ {
++ xclose (result.stdout_pipe[0]);
++ xclose (result.stderr_pipe[0]);
++ xdup2 (result.stdout_pipe[1], STDOUT_FILENO);
++ xdup2 (result.stderr_pipe[1], STDERR_FILENO);
++ xclose (result.stdout_pipe[1]);
++ xclose (result.stderr_pipe[1]);
++ callback (closure);
++ _exit (0);
++ }
++ xclose (result.stdout_pipe[1]);
++ xclose (result.stderr_pipe[1]);
++
++ return result;
++}
++
++struct support_subprocess
++support_subprogram (const char *file, char *const argv[])
++{
++ struct support_subprocess result = support_suprocess_init ();
++
++ posix_spawn_file_actions_t fa;
++ /* posix_spawn_file_actions_init does not fail. */
++ posix_spawn_file_actions_init (&fa);
++
++ xposix_spawn_file_actions_addclose (&fa, result.stdout_pipe[0]);
++ xposix_spawn_file_actions_addclose (&fa, result.stderr_pipe[0]);
++ xposix_spawn_file_actions_adddup2 (&fa, result.stdout_pipe[1], STDOUT_FILENO);
++ xposix_spawn_file_actions_adddup2 (&fa, result.stderr_pipe[1], STDERR_FILENO);
++ xposix_spawn_file_actions_addclose (&fa, result.stdout_pipe[1]);
++ xposix_spawn_file_actions_addclose (&fa, result.stderr_pipe[1]);
++
++ result.pid = xposix_spawn (file, &fa, NULL, argv, NULL);
++
++ xclose (result.stdout_pipe[1]);
++ xclose (result.stderr_pipe[1]);
++
++ return result;
++}
++
++int
++support_process_wait (struct support_subprocess *proc)
++{
++ xclose (proc->stdout_pipe[0]);
++ xclose (proc->stderr_pipe[0]);
++
++ int status;
++ xwaitpid (proc->pid, &status, 0);
++ return status;
++}
++
++
++static bool
++support_process_kill (int pid, int signo, int *status)
++{
++ /* Kill the whole process group. */
++ kill (-pid, signo);
++ /* In case setpgid failed in the child, kill it individually too. */
++ kill (pid, signo);
++
++ /* Wait for it to terminate. */
++ pid_t killed;
++ for (int i = 0; i < 5; ++i)
++ {
++ int status;
++ killed = xwaitpid (pid, &status, WNOHANG|WUNTRACED);
++ if (killed != 0)
++ break;
++
++ /* Delay, give the system time to process the kill. If the
++ nanosleep() call return prematurely, all the better. We
++ won't restart it since this probably means the child process
++ finally died. */
++ nanosleep (&((struct timespec) { 0, 100000000 }), NULL);
++ }
++ if (killed != 0 && killed != pid)
++ return false;
++
++ return true;
++}
++
++int
++support_process_terminate (struct support_subprocess *proc)
++{
++ xclose (proc->stdout_pipe[0]);
++ xclose (proc->stderr_pipe[0]);
++
++ int status;
++ pid_t killed = xwaitpid (proc->pid, &status, WNOHANG|WUNTRACED);
++ if (killed != 0 && killed == proc->pid)
++ return status;
++
++ /* Subprocess is still running, terminate it. */
++ if (!support_process_kill (proc->pid, SIGTERM, &status) )
++ support_process_kill (proc->pid, SIGKILL, &status);
++
++ return status;
++}
+diff --git a/support/tst-support_capture_subprocess.c b/support/tst-support_capture_subprocess.c
+index d8ba42ea8b..ab363e41ac 100644
+--- a/support/tst-support_capture_subprocess.c
++++ b/support/tst-support_capture_subprocess.c
+@@ -23,8 +23,20 @@
+ #include <support/capture_subprocess.h>
+ #include <support/check.h>
+ #include <support/support.h>
++#include <support/temp_file.h>
+ #include <sys/wait.h>
+ #include <unistd.h>
++#include <paths.h>
++#include <getopt.h>
++#include <limits.h>
++#include <errno.h>
++#include <array_length.h>
++
++/* Nonzero if the program gets called via 'exec'. */
++static int restart;
++
++/* Hold the four initial argument used to respawn the process. */
++static char *initial_argv[5];
+
+ /* Write one byte at *P to FD and advance *P. Do nothing if *P is
+ '\0'. */
+@@ -42,6 +54,30 @@ transfer (const unsigned char **p, int fd)
+ enum write_mode { out_first, err_first, interleave,
+ write_mode_last = interleave };
+
++static const char *
++write_mode_to_str (enum write_mode mode)
++{
++ switch (mode)
++ {
++ case out_first: return "out_first";
++ case err_first: return "err_first";
++ case interleave: return "interleave";
++ default: return "write_mode_last";
++ }
++}
++
++static enum write_mode
++str_to_write_mode (const char *mode)
++{
++ if (strcmp (mode, "out_first") == 0)
++ return out_first;
++ else if (strcmp (mode, "err_first") == 0)
++ return err_first;
++ else if (strcmp (mode, "interleave") == 0)
++ return interleave;
++ return write_mode_last;
++}
++
+ /* Describe what to write in the subprocess. */
+ struct test
+ {
+@@ -52,11 +88,9 @@ struct test
+ int status;
+ };
+
+-/* For use with support_capture_subprocess. */
+-static void
+-callback (void *closure)
++_Noreturn static void
++test_common (const struct test *test)
+ {
+- const struct test *test = closure;
+ bool mode_ok = false;
+ switch (test->write_mode)
+ {
+@@ -95,6 +129,40 @@ callback (void *closure)
+ exit (test->status);
+ }
+
++static int
++parse_int (const char *str)
++{
++ char *endptr;
++ long int ret = strtol (str, &endptr, 10);
++ TEST_COMPARE (errno, 0);
++ TEST_VERIFY (ret >= 0 && ret <= INT_MAX);
++ return ret;
++}
++
++/* For use with support_capture_subprogram. */
++_Noreturn static void
++handle_restart (char *out, char *err, const char *write_mode,
++ const char *signal, const char *status)
++{
++ struct test test =
++ {
++ out,
++ err,
++ str_to_write_mode (write_mode),
++ parse_int (signal),
++ parse_int (status)
++ };
++ test_common (&test);
++}
++
++/* For use with support_capture_subprocess. */
++_Noreturn static void
++callback (void *closure)
++{
++ const struct test *test = closure;
++ test_common (test);
++}
++
+ /* Create a heap-allocated random string of letters. */
+ static char *
+ random_string (size_t length)
+@@ -130,12 +198,59 @@ check_stream (const char *what, const struct xmemstream *stream,
+ }
+ }
+
++static struct support_capture_subprocess
++do_subprocess (struct test *test)
++{
++ return support_capture_subprocess (callback, test);
++}
++
++static struct support_capture_subprocess
++do_subprogram (const struct test *test)
++{
++ /* Three digits per byte plus null terminator. */
++ char signalstr[3 * sizeof(int) + 1];
++ snprintf (signalstr, sizeof (signalstr), "%d", test->signal);
++ char statusstr[3 * sizeof(int) + 1];
++ snprintf (statusstr, sizeof (statusstr), "%d", test->status);
++
++ int argc = 0;
++ enum {
++ /* 4 elements from initial_argv (path to ld.so, '--library-path', the
++ path', and application name'), 2 for restart argument ('--direct',
++ '--restart'), 5 arguments plus NULL. */
++ argv_size = 12
++ };
++ char *args[argv_size];
++
++ for (char **arg = initial_argv; *arg != NULL; arg++)
++ args[argc++] = *arg;
++
++ args[argc++] = (char*) "--direct";
++ args[argc++] = (char*) "--restart";
++
++ args[argc++] = test->out;
++ args[argc++] = test->err;
++ args[argc++] = (char*) write_mode_to_str (test->write_mode);
++ args[argc++] = signalstr;
++ args[argc++] = statusstr;
++ args[argc] = NULL;
++ TEST_VERIFY (argc < argv_size);
++
++ return support_capture_subprogram (args[0], args);
++}
++
++enum test_type
++{
++ subprocess,
++ subprogram,
++};
++
+ static int
+-do_test (void)
++do_multiple_tests (enum test_type type)
+ {
+ const int lengths[] = {0, 1, 17, 512, 20000, -1};
+
+- /* Test multiple combinations of support_capture_subprocess.
++ /* Test multiple combinations of support_capture_sub{process,program}.
+
+ length_idx_stdout: Index into the lengths array above,
+ controls how many bytes are written by the subprocess to
+@@ -164,8 +279,10 @@ do_test (void)
+ TEST_VERIFY (strlen (test.out) == lengths[length_idx_stdout]);
+ TEST_VERIFY (strlen (test.err) == lengths[length_idx_stderr]);
+
+- struct support_capture_subprocess result
+- = support_capture_subprocess (callback, &test);
++ struct support_capture_subprocess result
++ = type == subprocess ? do_subprocess (&test)
++ : do_subprogram (&test);
++
+ check_stream ("stdout", &result.out, test.out);
+ check_stream ("stderr", &result.err, test.err);
+
+@@ -199,4 +316,54 @@ do_test (void)
+ return 0;
+ }
+
++static int
++do_test (int argc, char *argv[])
++{
++ /* We must have either:
++
++ - one or four parameters if called initially:
++ + argv[1]: path for ld.so optional
++ + argv[2]: "--library-path" optional
++ + argv[3]: the library path optional
++ + argv[4]: the application name
++
++ - six parameters left if called through re-execution:
++ + argv[1]: the application name
++ + argv[2]: the stdout to print
++ + argv[3]: the stderr to print
++ + argv[4]: the write mode to use
++ + argv[5]: the signal to issue
++ + argv[6]: the exit status code to use
++
++ * When built with --enable-hardcoded-path-in-tests or issued without
++ using the loader directly.
++ */
++
++ if (argc != (restart ? 6 : 5) && argc != (restart ? 6 : 2))
++ FAIL_EXIT1 ("wrong number of arguments (%d)", argc);
++
++ if (restart)
++ {
++ handle_restart (argv[1], /* stdout */
++ argv[2], /* stderr */
++ argv[3], /* write_mode */
++ argv[4], /* signal */
++ argv[5]); /* status */
++ }
++
++ initial_argv[0] = argv[1]; /* path for ld.so */
++ initial_argv[1] = argv[2]; /* "--library-path" */
++ initial_argv[2] = argv[3]; /* the library path */
++ initial_argv[3] = argv[4]; /* the application name */
++ initial_argv[4] = NULL;
++
++ do_multiple_tests (subprocess);
++ do_multiple_tests (subprogram);
++
++ return 0;
++}
++
++#define CMDLINE_OPTIONS \
++ { "restart", no_argument, &restart, 1 },
++#define TEST_FUNCTION_ARGV do_test
+ #include <support/test-driver.c>
+diff --git a/support/xposix_spawn.c b/support/xposix_spawn.c
+new file mode 100644
+index 0000000000..e846017632
+--- /dev/null
++++ b/support/xposix_spawn.c
+@@ -0,0 +1,32 @@
++/* xposix_spawn implementation.
++ Copyright (C) 2019 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, see
++ <http://www.gnu.org/licenses/>. */
++
++#include <support/xspawn.h>
++#include <support/check.h>
++
++pid_t
++xposix_spawn (const char *file, const posix_spawn_file_actions_t *fa,
++ const posix_spawnattr_t *attr, char *const args[],
++ char *const envp[])
++{
++ pid_t pid;
++ int status = posix_spawn (&pid, file, fa, attr, args, envp);
++ if (status != 0)
++ FAIL_EXIT1 ("posix_spawn to %s file failed: %m", file);
++ return pid;
++}
+diff --git a/support/xposix_spawn_file_actions_addclose.c b/support/xposix_spawn_file_actions_addclose.c
+new file mode 100644
+index 0000000000..eed54a6514
+--- /dev/null
++++ b/support/xposix_spawn_file_actions_addclose.c
+@@ -0,0 +1,29 @@
++/* xposix_spawn_file_actions_addclose implementation.
++ Copyright (C) 2019 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, see
++ <http://www.gnu.org/licenses/>. */
++
++#include <support/xspawn.h>
++#include <support/check.h>
++
++int
++xposix_spawn_file_actions_addclose (posix_spawn_file_actions_t *fa, int fd)
++{
++ int status = posix_spawn_file_actions_addclose (fa, fd);
++ if (status == -1)
++ FAIL_EXIT1 ("posix_spawn_file_actions_addclose failed: %m\n");
++ return status;
++}
+diff --git a/support/xposix_spawn_file_actions_adddup2.c b/support/xposix_spawn_file_actions_adddup2.c
+new file mode 100644
+index 0000000000..a43b6490be
+--- /dev/null
++++ b/support/xposix_spawn_file_actions_adddup2.c
+@@ -0,0 +1,30 @@
++/* xposix_spawn_file_actions_adddup2 implementation.
++ Copyright (C) 2019 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, see
++ <http://www.gnu.org/licenses/>. */
++
++#include <support/xspawn.h>
++#include <support/check.h>
++
++int
++xposix_spawn_file_actions_adddup2 (posix_spawn_file_actions_t *fa, int fd,
++ int newfd)
++{
++ int status = posix_spawn_file_actions_adddup2 (fa, fd, newfd);
++ if (status == -1)
++ FAIL_EXIT1 ("posix_spawn_file_actions_adddup2 failed: %m\n");
++ return status;
++}
+diff --git a/support/xpthread_rwlock_destroy.c b/support/xpthread_rwlock_destroy.c
+new file mode 100644
+index 0000000000..6d6e953569
+--- /dev/null
++++ b/support/xpthread_rwlock_destroy.c
+@@ -0,0 +1,26 @@
++/* pthread_rwlock_destroy with error checking.
++ Copyright (C) 2019 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, see
++ <http://www.gnu.org/licenses/>. */
++
++#include <support/xthread.h>
++
++void
++xpthread_rwlock_destroy (pthread_rwlock_t *rwlock)
++{
++ xpthread_check_return ("pthread_rwlock_destroy",
++ pthread_rwlock_destroy (rwlock));
++}
+diff --git a/support/xspawn.h b/support/xspawn.h
+new file mode 100644
+index 0000000000..bbf89132e4
+--- /dev/null
++++ b/support/xspawn.h
+@@ -0,0 +1,34 @@
++/* posix_spawn with support checks.
++ Copyright (C) 2019 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, see
++ <http://www.gnu.org/licenses/>. */
++
++#ifndef SUPPORT_XSPAWN_H
++#define SUPPORT_XSPAWN_H
++
++#include <spawn.h>
++
++__BEGIN_DECLS
++
++int xposix_spawn_file_actions_addclose (posix_spawn_file_actions_t *, int);
++int xposix_spawn_file_actions_adddup2 (posix_spawn_file_actions_t *, int, int);
++
++pid_t xposix_spawn (const char *, const posix_spawn_file_actions_t *,
++ const posix_spawnattr_t *, char *const [], char *const []);
++
++__END_DECLS
++
++#endif
+diff --git a/support/xthread.h b/support/xthread.h
+index 47c23235f3..9fe1f68b3b 100644
+--- a/support/xthread.h
++++ b/support/xthread.h
+@@ -84,6 +84,7 @@ void xpthread_rwlockattr_setkind_np (pthread_rwlockattr_t *attr, int pref);
+ void xpthread_rwlock_wrlock (pthread_rwlock_t *rwlock);
+ void xpthread_rwlock_rdlock (pthread_rwlock_t *rwlock);
+ void xpthread_rwlock_unlock (pthread_rwlock_t *rwlock);
++void xpthread_rwlock_destroy (pthread_rwlock_t *rwlock);
+
+ __END_DECLS
+
+diff --git a/sysdeps/arm/stap-probe-machine.h b/sysdeps/arm/stap-probe-machine.h
+new file mode 100644
+index 0000000000..d27ca22040
+--- /dev/null
++++ b/sysdeps/arm/stap-probe-machine.h
+@@ -0,0 +1,22 @@
++/* Macros for customizing Systemtap <sys/sdt.h>. Arm version.
++ Copyright (C) 2019 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, see
++ <http://www.gnu.org/licenses/>. */
++
++/* The default "nor" constraint produces unparseable memory references
++ for constants. Omit the problematic "o" constraint. See bug 24164
++ and GCC PR 89146. */
++#define STAP_SDT_ARG_CONSTRAINT nr
+diff --git a/sysdeps/generic/stap-probe-machine.h b/sysdeps/generic/stap-probe-machine.h
+new file mode 100644
+index 0000000000..2e5790c3b2
+--- /dev/null
++++ b/sysdeps/generic/stap-probe-machine.h
+@@ -0,0 +1,19 @@
++/* Macros for customizing Systemtap <sys/sdt.h>. Generic version.
++ Copyright (C) 2019 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, see
++ <http://www.gnu.org/licenses/>. */
++
++/* By default, there are no customizations. */
+diff --git a/sysdeps/nptl/fork.c b/sysdeps/nptl/fork.c
+index bd68f18b45..14b69a6f89 100644
+--- a/sysdeps/nptl/fork.c
++++ b/sysdeps/nptl/fork.c
+@@ -55,7 +55,7 @@ __libc_fork (void)
+ but our current fork implementation is not. */
+ bool multiple_threads = THREAD_GETMEM (THREAD_SELF, header.multiple_threads);
+
+- __run_fork_handlers (atfork_run_prepare);
++ __run_fork_handlers (atfork_run_prepare, multiple_threads);
+
+ /* If we are not running multiple threads, we do not have to
+ preserve lock state. If fork runs from a signal handler, only
+@@ -134,7 +134,7 @@ __libc_fork (void)
+ __rtld_lock_initialize (GL(dl_load_lock));
+
+ /* Run the handlers registered for the child. */
+- __run_fork_handlers (atfork_run_child);
++ __run_fork_handlers (atfork_run_child, multiple_threads);
+ }
+ else
+ {
+@@ -149,7 +149,7 @@ __libc_fork (void)
+ }
+
+ /* Run the handlers registered for the parent. */
+- __run_fork_handlers (atfork_run_parent);
++ __run_fork_handlers (atfork_run_parent, multiple_threads);
+ }
+
+ return pid;
+diff --git a/sysdeps/nptl/fork.h b/sysdeps/nptl/fork.h
+index a1c3b26b68..99ed76034b 100644
+--- a/sysdeps/nptl/fork.h
++++ b/sysdeps/nptl/fork.h
+@@ -52,9 +52,11 @@ enum __run_fork_handler_type
+ - atfork_run_child: run all the CHILD_HANDLER and unlocks the internal
+ lock.
+ - atfork_run_parent: run all the PARENT_HANDLER and unlocks the internal
+- lock. */
+-extern void __run_fork_handlers (enum __run_fork_handler_type who)
+- attribute_hidden;
++ lock.
++
++ Perform locking only if DO_LOCKING. */
++extern void __run_fork_handlers (enum __run_fork_handler_type who,
++ _Bool do_locking) attribute_hidden;
+
+ /* C library side function to register new fork handlers. */
+ extern int __register_atfork (void (*__prepare) (void),
+diff --git a/sysdeps/powerpc/dl-procinfo.h b/sysdeps/powerpc/dl-procinfo.h
+index f542f7318f..dfc3b33a72 100644
+--- a/sysdeps/powerpc/dl-procinfo.h
++++ b/sysdeps/powerpc/dl-procinfo.h
+@@ -225,7 +225,7 @@ _dl_procinfo (unsigned int type, unsigned long int word)
+ break;
+ }
+ default:
+- /* This should not happen. */
++ /* Fallback to generic output mechanism. */
+ return -1;
+ }
+ _dl_printf ("\n");
+diff --git a/sysdeps/s390/dl-procinfo.h b/sysdeps/s390/dl-procinfo.h
+index b4b81fc70a..99697ae649 100644
+--- a/sysdeps/s390/dl-procinfo.h
++++ b/sysdeps/s390/dl-procinfo.h
+@@ -57,7 +57,8 @@ enum
+ };
+
+ #define HWCAP_IMPORTANT (HWCAP_S390_ZARCH | HWCAP_S390_LDISP \
+- | HWCAP_S390_EIMM | HWCAP_S390_DFP)
++ | HWCAP_S390_EIMM | HWCAP_S390_DFP \
++ | HWCAP_S390_VX | HWCAP_S390_VXE)
+
+ /* We cannot provide a general printing function. */
+ #define _dl_procinfo(type, word) -1
+diff --git a/sysdeps/sparc/dl-procinfo.h b/sysdeps/sparc/dl-procinfo.h
+index 282b8c5117..64ee267fc7 100644
+--- a/sysdeps/sparc/dl-procinfo.h
++++ b/sysdeps/sparc/dl-procinfo.h
+@@ -31,8 +31,8 @@ _dl_procinfo (unsigned int type, unsigned long int word)
+ {
+ int i;
+
+- /* Fallback to unknown output mechanism. */
+- if (type == AT_HWCAP2)
++ /* Fallback to generic output mechanism. */
++ if (type != AT_HWCAP)
+ return -1;
+
+ _dl_printf ("AT_HWCAP: ");
+diff --git a/sysdeps/unix/sysv/linux/arm/dl-procinfo.h b/sysdeps/unix/sysv/linux/arm/dl-procinfo.h
+index 66c00297b7..05c62c8687 100644
+--- a/sysdeps/unix/sysv/linux/arm/dl-procinfo.h
++++ b/sysdeps/unix/sysv/linux/arm/dl-procinfo.h
+@@ -67,7 +67,7 @@ _dl_procinfo (unsigned int type, unsigned long int word)
+ break;
+ }
+ default:
+- /* This should not happen. */
++ /* Fallback to generic output mechanism. */
+ return -1;
+ }
+ _dl_printf ("\n");
+diff --git a/sysdeps/unix/sysv/linux/i386/dl-procinfo.h b/sysdeps/unix/sysv/linux/i386/dl-procinfo.h
+index 22b43431bc..0585cdaa9c 100644
+--- a/sysdeps/unix/sysv/linux/i386/dl-procinfo.h
++++ b/sysdeps/unix/sysv/linux/i386/dl-procinfo.h
+@@ -30,8 +30,8 @@ _dl_procinfo (unsigned int type, unsigned long int word)
+ in the kernel sources. */
+ int i;
+
+- /* Fallback to unknown output mechanism. */
+- if (type == AT_HWCAP2)
++ /* Fallback to generic output mechanism. */
++ if (type != AT_HWCAP)
+ return -1;
+
+ _dl_printf ("AT_HWCAP: ");
+diff --git a/sysdeps/unix/sysv/linux/s390/dl-procinfo.h b/sysdeps/unix/sysv/linux/s390/dl-procinfo.h
+index 19329a335b..d67fde368f 100644
+--- a/sysdeps/unix/sysv/linux/s390/dl-procinfo.h
++++ b/sysdeps/unix/sysv/linux/s390/dl-procinfo.h
+@@ -32,8 +32,8 @@ _dl_procinfo (unsigned int type, unsigned long int word)
+ in the kernel sources. */
+ int i;
+
+- /* Fallback to unknown output mechanism. */
+- if (type == AT_HWCAP2)
++ /* Fallback to generic output mechanism. */
++ if (type != AT_HWCAP)
+ return -1;
+
+ _dl_printf ("AT_HWCAP: ");
+diff --git a/sysdeps/x86_64/memcmp.S b/sysdeps/x86_64/memcmp.S
+index 1fc487caa5..1322bb3b92 100644
+--- a/sysdeps/x86_64/memcmp.S
++++ b/sysdeps/x86_64/memcmp.S
+@@ -21,14 +21,18 @@
+
+ .text
+ ENTRY (memcmp)
+- test %rdx, %rdx
++#ifdef __ILP32__
++ /* Clear the upper 32 bits. */
++ movl %edx, %edx
++#endif
++ test %RDX_LP, %RDX_LP
+ jz L(finz)
+ cmpq $1, %rdx
+- jle L(finr1b)
++ jbe L(finr1b)
+ subq %rdi, %rsi
+ movq %rdx, %r10
+ cmpq $32, %r10
+- jge L(gt32)
++ jae L(gt32)
+ /* Handle small chunks and last block of less than 32 bytes. */
+ L(small):
+ testq $1, %r10
+@@ -156,7 +160,7 @@ L(A32):
+ movq %r11, %r10
+ andq $-32, %r10
+ cmpq %r10, %rdi
+- jge L(mt16)
++ jae L(mt16)
+ /* Pre-unroll to be ready for unrolled 64B loop. */
+ testq $32, %rdi
+ jz L(A64)
+@@ -178,7 +182,7 @@ L(A64):
+ movq %r11, %r10
+ andq $-64, %r10
+ cmpq %r10, %rdi
+- jge L(mt32)
++ jae L(mt32)
+
+ L(A64main):
+ movdqu (%rdi,%rsi), %xmm0
+@@ -216,7 +220,7 @@ L(mt32):
+ movq %r11, %r10
+ andq $-32, %r10
+ cmpq %r10, %rdi
+- jge L(mt16)
++ jae L(mt16)
+
+ L(A32main):
+ movdqu (%rdi,%rsi), %xmm0
+@@ -254,7 +258,7 @@ L(ATR):
+ movq %r11, %r10
+ andq $-32, %r10
+ cmpq %r10, %rdi
+- jge L(mt16)
++ jae L(mt16)
+ testq $16, %rdi
+ jz L(ATR32)
+
+@@ -325,7 +329,7 @@ L(ATR64main):
+ movq %r11, %r10
+ andq $-32, %r10
+ cmpq %r10, %rdi
+- jge L(mt16)
++ jae L(mt16)
+
+ L(ATR32res):
+ movdqa (%rdi,%rsi), %xmm0
+diff --git a/sysdeps/x86_64/x32/Makefile b/sysdeps/x86_64/x32/Makefile
+index 1557724b0c..8748956563 100644
+--- a/sysdeps/x86_64/x32/Makefile
++++ b/sysdeps/x86_64/x32/Makefile
+@@ -8,7 +8,8 @@ endif
+ ifeq ($(subdir),string)
+ tests += tst-size_t-memchr tst-size_t-memcmp tst-size_t-memcpy \
+ tst-size_t-memrchr tst-size_t-memset tst-size_t-strncasecmp \
+- tst-size_t-strncmp tst-size_t-strncpy tst-size_t-strnlen
++ tst-size_t-strncmp tst-size_t-strncpy tst-size_t-strnlen \
++ tst-size_t-memcmp-2
+ endif
+
+ ifeq ($(subdir),wcsmbs)
+diff --git a/sysdeps/x86_64/x32/tst-size_t-memcmp-2.c b/sysdeps/x86_64/x32/tst-size_t-memcmp-2.c
+new file mode 100644
+index 0000000000..d8ae1a0813
+--- /dev/null
++++ b/sysdeps/x86_64/x32/tst-size_t-memcmp-2.c
+@@ -0,0 +1,79 @@
++/* Test memcmp with size_t in the lower 32 bits of 64-bit register.
++ Copyright (C) 2019 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, see
++ <http://www.gnu.org/licenses/>. */
++
++#define TEST_MAIN
++#ifdef WIDE
++# define TEST_NAME "wmemcmp"
++#else
++# define TEST_NAME "memcmp"
++#endif
++
++#include "test-size_t.h"
++
++#ifdef WIDE
++# include <inttypes.h>
++# include <wchar.h>
++
++# define MEMCMP wmemcmp
++# define CHAR wchar_t
++#else
++# define MEMCMP memcmp
++# define CHAR char
++#endif
++
++IMPL (MEMCMP, 1)
++
++typedef int (*proto_t) (const CHAR *, const CHAR *, size_t);
++
++static int
++__attribute__ ((noinline, noclone))
++do_memcmp (parameter_t a, parameter_t b)
++{
++ return CALL (&b, a.p, b.p, a.len);
++}
++
++static int
++test_main (void)
++{
++ test_init ();
++
++ parameter_t dest = { { page_size / sizeof (CHAR) }, buf1 };
++ parameter_t src = { { 0 }, buf2 };
++
++ memcpy (buf1, buf2, page_size);
++
++ CHAR *p = (CHAR *) buf1;
++ p[page_size / sizeof (CHAR) - 1] = (CHAR) 1;
++
++ int ret = 0;
++ FOR_EACH_IMPL (impl, 0)
++ {
++ src.fn = impl->fn;
++ int res = do_memcmp (dest, src);
++ if (res >= 0)
++ {
++ error (0, 0, "Wrong result in function %s: %i >= 0",
++ impl->name, res);
++ ret = 1;
++ }
++ }
++
++ return ret ? EXIT_FAILURE : EXIT_SUCCESS;
++}
++
++#include <support/test-driver.c>