diff options
author | Tavian Barnes | 2019-07-04 15:25:01 -0400 |
---|---|---|
committer | Tavian Barnes | 2019-07-04 15:25:01 -0400 |
commit | 363e369b0d94b0b33328597f90a0a910056b7990 (patch) | |
tree | a3f72cff32e1581696b8928878e0cd0a13e18c19 /glibc-34fb5f61d3c3f4b8fc616ea259fa19168b58ecd4.patch | |
parent | cbacff4f8fa16e713686e844f163c492c1c35333 (diff) | |
download | aur-363e369b0d94b0b33328597f90a0a910056b7990.tar.gz |
Bump to 2.29-3
Diffstat (limited to 'glibc-34fb5f61d3c3f4b8fc616ea259fa19168b58ecd4.patch')
-rw-r--r-- | glibc-34fb5f61d3c3f4b8fc616ea259fa19168b58ecd4.patch | 4059 |
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> |