diff --git a/glibc-2.25-posix-spawn-fix.patch b/glibc-2.25-posix-spawn-fix.patch deleted file mode 100644 index f7a8037..0000000 --- a/glibc-2.25-posix-spawn-fix.patch +++ /dev/null @@ -1,141 +0,0 @@ -From fe05e1cb6d64dba6172249c79526f1e9af8f2bfd Mon Sep 17 00:00:00 2001 -From: Adhemerval Zanella -Date: Thu, 12 Oct 2017 15:20:57 -0300 -Subject: [PATCH] posix: Fix improper assert in Linux posix_spawn (BZ#22273) - -As noted by Florian Weimer, current Linux posix_spawn implementation -can trigger an assert if the auxiliary process is terminated before -actually setting the err member: - - 340 /* Child must set args.err to something non-negative - we rely on - 341 the parent and child sharing VM. */ - 342 args.err = -1; - [...] - 362 new_pid = CLONE (__spawni_child, STACK (stack, stack_size), stack_size, - 363 CLONE_VM | CLONE_VFORK | SIGCHLD, &args); - 364 - 365 if (new_pid > 0) - 366 { - 367 ec = args.err; - 368 assert (ec >= 0); - -Another possible issue is killing the child between setting the err and -actually calling execve. In this case the process will not ran, but -posix_spawn also will not report any error: - - 269 - 270 args->err = 0; - 271 args->exec (args->file, args->argv, args->envp); - -As suggested by Andreas Schwab, this patch removes the faulty assert -and also handles any signal that happens before fork and execve as the -spawn was successful (and thus relaying the handling to the caller to -figure this out). Different than Florian, I can not see why using -atomics to set err would help here, essentially the code runs -sequentially (due CLONE_VFORK) and I think it would not be legal the -compiler evaluate ec without checking for new_pid result (thus there -is no need to compiler barrier). - -Summarizing the possible scenarios on posix_spawn execution, we -have: - - 1. For default case with a success execution, args.err will be 0, pid - will not be collected and it will be reported to caller. - - 2. For default failure case, args.err will be positive and the it will - be collected by the waitpid. An error will be reported to the - caller. - - 3. For the unlikely case where the process was terminated and not - collected by a caller signal handler, it will be reported as succeful - execution and not be collected by posix_spawn (since args.err will - be 0). The caller will need to actually handle this case. - - 4. For the unlikely case where the process was terminated and collected - by caller we have 3 other possible scenarios: - - 4.1. The auxiliary process was terminated with args.err equal to 0: - it will handled as 1. (so it does not matter if we hit the pid - reuse race since we won't possible collect an unexpected - process). - - 4.2. The auxiliary process was terminated after execve (due a failure - in calling it) and before setting args.err to -1: it will also - be handle as 1. but with the issue of not be able to report the - caller a possible execve failures. - - 4.3. The auxiliary process was terminated after args.err is set to -1: - this is the case where it will be possible to hit the pid reuse - case where we will need to collected the auxiliary pid but we - can not be sure if it will be expected one. I think for this - case we need to actually change waitpid to use WNOHANG to avoid - hanging indefinitely on the call and report an error to caller - since we can't differentiate between a default failure as 2. - and a possible pid reuse race issue. - -Checked on x86_64-linux-gnu. - - * sysdeps/unix/sysv/linux/spawni.c (__spawnix): Handle the case where - the auxiliary process is terminated by a signal before calling _exit - or execve. -diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c -index dea1650..d15fbb1 100644 ---- a/sysdeps/unix/sysv/linux/spawni.c -+++ b/sysdeps/unix/sysv/linux/spawni.c -@@ -17,7 +17,6 @@ - . */ - - #include --#include - #include - #include - #include -@@ -268,7 +267,6 @@ __spawni_child (void *arguments) - __sigprocmask (SIG_SETMASK, (attr->__flags & POSIX_SPAWN_SETSIGMASK) - ? &attr->__ss : &args->oldmask, 0); - -- args->err = 0; - args->exec (args->file, args->argv, args->envp); - - /* This is compatibility function required to enable posix_spawn run -@@ -339,7 +337,7 @@ __spawnix (pid_t * pid, const char *file, - - /* Child must set args.err to something non-negative - we rely on - the parent and child sharing VM. */ -- args.err = -1; -+ args.err = 0; - args.file = file; - args.exec = exec; - args.fa = file_actions; -@@ -362,12 +360,26 @@ __spawnix (pid_t * pid, const char *file, - new_pid = CLONE (__spawni_child, STACK (stack, stack_size), stack_size, - CLONE_VM | CLONE_VFORK | SIGCHLD, &args); - -+ /* It needs to collect the case where the auxiliary process was created -+ but failed to execute the file (due either any preparation step or -+ for execve itself). */ - if (new_pid > 0) - { -+ /* Also, it handles the unlikely case where the auxiliary process was -+ terminated before calling execve as if it was successfully. The -+ args.err is set to 0 as default and changed to a positive value -+ only in case of failure, so in case of premature termination -+ due a signal args.err will remain zeroed and it will be up to -+ caller to actually collect it. */ - ec = args.err; -- assert (ec >= 0); -- if (ec != 0) -- __waitpid (new_pid, NULL, 0); -+ if (ec > 0) -+ /* There still an unlikely case where the child is cancelled after -+ setting args.err, due to a positive error value. Also due a -+ possible pid reuse race (where the kernel allocated the same pid -+ to unrelated process) we need not to undefinitely hang expecting -+ an invalid pid. In both cases an error is returned to the -+ caller. */ -+ __waitpid (new_pid, NULL, WNOHANG); - } - else - ec = -new_pid; --- -2.9.3 diff --git a/glibc.changes b/glibc.changes index df0548b..1cc7f4b 100644 --- a/glibc.changes +++ b/glibc.changes @@ -1,3 +1,8 @@ +* Fri Mar 15 2019 Marko Saukko - 2.25+git4 +- Apply 2.25.6 patch set from ubuntu. Contributes to JB#45152 +- Fixes CVE-2017-15670, CVE-2017-15671, CVE-2017-15804, + CVE-2017-1000408, CVE-2017-1000409, CVE-2017-16997 + * Mon Feb 18 2019 Tomi Leppänen - 2.25+git3 - Add glibc-doc subpackage. Contributes to JB#24119 diff --git a/glibc.spec b/glibc.spec index dba80a4..3eb91db 100644 --- a/glibc.spec +++ b/glibc.spec @@ -1,7 +1,7 @@ Name: glibc Summary: GNU C library shared libraries -Version: 2.25+git3 +Version: 2.25+git4 Release: 0 License: LGPLv2+ and LGPLv2+ with exceptions and GPLv2+ Group: System/Libraries @@ -21,7 +21,7 @@ Patch9: glibc-2.14-locarchive-fedora.patch Patch10: eglibc-2.15-fix-neon-libdl.patch Patch11: eglibc-2.19-shlib-make.patch Patch12: glibc-2.25-bits.patch -Patch13: glibc-2.25-posix-spawn-fix.patch +Patch13: ubuntu-2.25.6-git-updates.diff Provides: ldconfig # The dynamic linker supports DT_GNU_HASH diff --git a/ubuntu-2.25.6-git-updates.diff b/ubuntu-2.25.6-git-updates.diff new file mode 100644 index 0000000..eaba5e3 --- /dev/null +++ b/ubuntu-2.25.6-git-updates.diff @@ -0,0 +1,14297 @@ +GIT update of git://sourceware.org/git/glibc.git/release/2.25/master from glibc-2.25 + +diff --git a/ChangeLog b/ChangeLog +index f140ee67de..a3db9c09f2 100644 +--- a/ChangeLog ++++ b/ChangeLog +@@ -1,3 +1,750 @@ ++2017-12-30 Aurelien Jarno ++ Dmitry V. Levin ++ ++ [BZ #22625] ++ * elf/dl-load.c (fillin_rpath): Check for empty tokens before dynamic ++ string token expansion. Check for NULL pointer or empty string possibly ++ returned by expand_dynamic_string_token. ++ (decompose_rpath): Check for empty path after dynamic string ++ token expansion. ++ ++2017-12-18 Dmitry V. Levin ++ ++ [BZ #22627] ++ * elf/dl-load.c (_dl_init_paths): Remove _dl_dst_substitute preparatory ++ code and invocation. ++ ++2017-12-14 Florian Weimer ++ ++ [BZ #22607] ++ CVE-2017-1000409 ++ * elf/dl-load.c (_dl_init_paths): Compute number of components in ++ the expanded path string. ++ ++2017-12-14 Florian Weimer ++ ++ [BZ #22606] ++ CVE-2017-1000408 ++ * elf/dl-load.c (system_dirs): Update comment. ++ (nsystem_dirs_len): Use array_length. ++ (_dl_init_paths): Use nsystem_dirs_len to compute the array size. ++ ++2017-11-02 Florian Weimer ++ ++ Add array_length and array_end macros. ++ * include/array_length.h: New file. ++ ++2017-12-12 James Clarke ++ ++ * sysdeps/unix/sysv/linux/ia64/ipc_priv.h: New file defining ++ __IPC_64 to 0 to avoid IPC_64 being set. ++ ++2017-11-02 Florian Weimer ++ ++ [BZ #22332] ++ * posix/tst-glob-tilde.c (do_noescape): New variable. ++ (one_test): Process it. ++ (do_test): Set do_noescape. Add unescaping test case. ++ ++2017-10-22 Paul Eggert ++ ++ [BZ #22332] ++ * posix/glob.c (__glob): Fix buffer overflow during GLOB_TILDE ++ unescaping. ++ ++2017-10-21 Florian Weimer ++ ++ * posix/Makefile (tests): Add tst-glob-tilde. ++ (tests-special): Add tst-glob-tilde-mem.out ++ (tst-glob-tilde-ENV): Set MALLOC_TRACE. ++ (tst-glob-tilde-mem.out): Add mtrace check. ++ * posix/tst-glob-tilde.c: New file. ++ ++2017-10-20 Paul Eggert ++ ++ [BZ #22320] ++ CVE-2017-15670 ++ * posix/glob.c (__glob): Fix one-byte overflow. ++ ++2017-09-08 Adhemerval Zanella ++ ++ [BZ #1062] ++ CVE-2017-15671 ++ * posix/Makefile (routines): Add globfree, globfree64, and ++ glob_pattern_p. ++ * posix/flexmember.h: New file. ++ * posix/glob_internal.h: Likewise. ++ * posix/glob_pattern_p.c: Likewise. ++ * posix/globfree.c: Likewise. ++ * posix/globfree64.c: Likewise. ++ * sysdeps/gnu/globfree64.c: Likewise. ++ * sysdeps/unix/sysv/linux/alpha/globfree.c: Likewise. ++ * sysdeps/unix/sysv/linux/mips/mips64/n64/globfree64.c: Likewise. ++ * sysdeps/unix/sysv/linux/oldglob.c: Likewise. ++ * sysdeps/unix/sysv/linux/wordsize-64/globfree64.c: Likewise. ++ * sysdeps/unix/sysv/linux/x86_64/x32/globfree.c: Likewise. ++ * sysdeps/wordsize-64/globfree.c: Likewise. ++ * sysdeps/wordsize-64/globfree64.c: Likewise. ++ * posix/glob.c (HAVE_CONFIG_H): Use !_LIBC instead. ++ [NDEBUG): Remove comments. ++ (GLOB_ONLY_P, _AMIGA, VMS): Remove define. ++ (dirent_type): New type. Use uint_fast8_t not ++ uint8_t, as C99 does not require uint8_t. ++ (DT_UNKNOWN, DT_DIR, DT_LNK): New macros. ++ (struct readdir_result): Use dirent_type. Do not define skip_entry ++ unless it is needed; this saves a byte on platforms lacking d_ino. ++ (readdir_result_type, readdir_result_skip_entry): ++ New functions, replacing ... ++ (readdir_result_might_be_symlink, readdir_result_might_be_dir): ++ these functions, which were removed. This makes the callers ++ easier to read. All callers changed. ++ (D_INO_TO_RESULT): Now empty if there is no d_ino. ++ (size_add_wrapv, glob_use_alloca): New static functions. ++ (glob, glob_in_dir): Check for size_t overflow in several places, ++ and fix some size_t checks that were not quite right. ++ Remove old code using SHELL since Bash no longer ++ uses this. ++ (glob, prefix_array): Separate MS code better. ++ (glob_in_dir): Remove old Amiga and VMS code. ++ (globfree, __glob_pattern_type, __glob_pattern_p): Move to ++ separate files. ++ (glob_in_dir): Do not rely on undefined behavior in accessing ++ struct members beyond their bounds. Use a flexible array member ++ instead ++ (link_stat): Rename from link_exists2_p and return -1/0 instead of ++ 0/1. Caller changed. ++ (glob): Fix memory leaks. ++ * posix/glob64 (globfree64): Move to separate file. ++ * sysdeps/gnu/glob64.c (NO_GLOB_PATTERN_P): Remove define. ++ (globfree64): Remove hidden alias. ++ * sysdeps/unix/sysv/linux/Makefile (sysdeps_routines): Add ++ oldglob. ++ * sysdeps/unix/sysv/linux/alpha/glob.c (__new_globfree): Move to ++ separate file. ++ * sysdeps/unix/sysv/linux/i386/glob64.c (NO_GLOB_PATTERN_P): Remove ++ define. ++ Move compat code to separate file. ++ * sysdeps/wordsize-64/glob.c (globfree): Move definitions to ++ separate file. ++ ++2017-08-20 H.J. Lu ++ ++ [BZ #18822] ++ * sysdeps/unix/sysv/linux/i386/glob64.c (__old_glob64): Add ++ libc_hidden_proto and libc_hidden_def. ++ ++2017-03-14 Adhemerval Zanella ++ ++ [BZ #21232] ++ * sysdeps/unix/sysv/linux/mips/mips64/n64/posix_fadvise64.c: Add ++ posix_fadvise64 weak_alias for static build. ++ ++2017-10-23 Adhemerval Zanella ++ ++ * sysdeps/unix/sysv/linux/spawni.c (__spawnix): Use 0 instead of ++ WNOHANG in waitpid call. ++ ++2017-10-20 Adhemerval Zanella ++ ++ [BZ #22273] ++ * sysdeps/unix/sysv/linux/spawni.c (__spawnix): Handle the case where ++ the auxiliary process is terminated by a signal before calling _exit ++ or execve. ++ ++2017-08-09 Andreas Schwab ++ ++ * nptl/Makefile (tests) [$(build-shared) = yes]: Add ++ tst-compat-forwarder. ++ (modules-names): Add tst-compat-forwarder-mod. ++ ($(objpfx)tst-compat-forwarder): Depend on ++ $(objpfx)tst-compat-forwarder-mod.so. ++ * nptl/tst-compat-forwarder.c: New file. ++ * nptl/tst-compat-forwarder-mod.c: New file. ++ ++2017-08-09 Andreas Schwab ++ ++ * sysdeps/unix/sysv/linux/s390/pt-longjmp.c: Update reference to ++ renamed alias. ++ ++2017-08-08 Andreas Schwab ++ ++ [BZ #21041] ++ * nptl/pt-longjmp.c (longjmp, siglongjmp): Don't use IFUNC resolver. ++ * nptl/pt-system.c (system): Likewise. ++ ++2017-10-13 James Clarke ++ ++ * sysdeps/powerpc/powerpc32/dl-machine.h (elf_machine_rela): ++ Assign sym_map to be map for local symbols, as TLS relocations ++ use sym_map to determine whether the symbol is defined and to ++ extract the TLS information. ++ * sysdeps/sparc/sparc32/dl-machine.h (elf_machine_rela): Likewise. ++ * sysdeps/sparc/sparc64/dl-machine.h (elf_machine_rela): Likewise. ++ ++2017-10-19 Joseph Myers ++ ++ [BZ #22322] ++ * sysdeps/mips/bits/long-double.h: Move to .... ++ * sysdeps/mips/ieee754/bits/long-double.h: ... here. ++ ++2017-10-22 H.J. Lu ++ ++ [BZ #21265] ++ * sysdeps/x86/cpu-features-offsets.sym (XSAVE_STATE_SIZE_OFFSET): ++ New. ++ * sysdeps/x86/cpu-features.c: Include . ++ (get_common_indeces): Set xsave_state_size and ++ bit_arch_XSAVEC_Usable if needed. ++ (init_cpu_features): Remove bit_arch_Use_dl_runtime_resolve_slow ++ and bit_arch_Use_dl_runtime_resolve_opt. ++ * sysdeps/x86/cpu-features.h (bit_arch_Use_dl_runtime_resolve_opt): ++ Removed. ++ (bit_arch_Use_dl_runtime_resolve_slow): Likewise. ++ (bit_arch_Prefer_No_AVX512): Updated. ++ (bit_arch_MathVec_Prefer_No_AVX512): Likewise. ++ (bit_arch_XSAVEC_Usable): New. ++ (STATE_SAVE_OFFSET): Likewise. ++ (STATE_SAVE_MASK): Likewise. ++ [__ASSEMBLER__]: Include . ++ (cpu_features): Add xsave_state_size. ++ (index_arch_Use_dl_runtime_resolve_opt): Removed. ++ (index_arch_Use_dl_runtime_resolve_slow): Likewise. ++ (index_arch_XSAVEC_Usable): New. ++ * sysdeps/x86_64/dl-machine.h (elf_machine_runtime_setup): ++ Replace _dl_runtime_resolve_sse, _dl_runtime_resolve_avx, ++ _dl_runtime_resolve_avx_slow, _dl_runtime_resolve_avx_opt, ++ _dl_runtime_resolve_avx512 and _dl_runtime_resolve_avx512_opt ++ with _dl_runtime_resolve_fxsave, _dl_runtime_resolve_xsave and ++ _dl_runtime_resolve_xsavec. ++ * sysdeps/x86_64/dl-trampoline.S (DL_RUNTIME_UNALIGNED_VEC_SIZE): ++ Removed. ++ (DL_RUNTIME_RESOLVE_REALIGN_STACK): Check STATE_SAVE_ALIGNMENT ++ instead of VEC_SIZE. ++ (REGISTER_SAVE_BND0): Removed. ++ (REGISTER_SAVE_BND1): Likewise. ++ (REGISTER_SAVE_BND3): Likewise. ++ (REGISTER_SAVE_RAX): Always defined to 0. ++ (VMOV): Removed. ++ (_dl_runtime_resolve_avx): Likewise. ++ (_dl_runtime_resolve_avx_slow): Likewise. ++ (_dl_runtime_resolve_avx_opt): Likewise. ++ (_dl_runtime_resolve_avx512): Likewise. ++ (_dl_runtime_resolve_avx512_opt): Likewise. ++ (_dl_runtime_resolve_sse): Likewise. ++ (_dl_runtime_resolve_sse_vex): Likewise. ++ (USE_FXSAVE): New. ++ (_dl_runtime_resolve_fxsave): Likewise. ++ (USE_XSAVE): Likewise. ++ (_dl_runtime_resolve_xsave): Likewise. ++ (USE_XSAVEC): Likewise. ++ (_dl_runtime_resolve_xsavec): Likewise. ++ * sysdeps/x86_64/dl-trampoline.h (_dl_runtime_resolve_avx512): ++ Removed. ++ (_dl_runtime_resolve_avx512_opt): Likewise. ++ (_dl_runtime_resolve_avx): Likewise. ++ (_dl_runtime_resolve_avx_opt): Likewise. ++ (_dl_runtime_resolve_sse): Likewise. ++ (_dl_runtime_resolve_sse_vex): Likewise. ++ (_dl_runtime_resolve_fxsave): New. ++ (_dl_runtime_resolve_xsave): Likewise. ++ (_dl_runtime_resolve_xsavec): Likewise. ++ ++2017-10-19 H.J. Lu ++ ++ * sysdeps/x86_64/Makefile (tests): Add tst-sse, tst-avx and ++ tst-avx512. ++ (test-extras): Add tst-avx-aux and tst-avx512-aux. ++ (extra-test-objs): Add tst-avx-aux.o and tst-avx512-aux.o. ++ (modules-names): Add tst-ssemod, tst-avxmod and tst-avx512mod. ++ ($(objpfx)tst-sse): New rule. ++ ($(objpfx)tst-avx): Likewise. ++ ($(objpfx)tst-avx512): Likewise. ++ (CFLAGS-tst-avx-aux.c): New. ++ (CFLAGS-tst-avxmod.c): Likewise. ++ (CFLAGS-tst-avx512-aux.c): Likewise. ++ (CFLAGS-tst-avx512mod.c): Likewise. ++ * sysdeps/x86_64/tst-avx-aux.c: New file. ++ * sysdeps/x86_64/tst-avx.c: Likewise. ++ * sysdeps/x86_64/tst-avx512-aux.c: Likewise. ++ * sysdeps/x86_64/tst-avx512.c: Likewise. ++ * sysdeps/x86_64/tst-avx512mod.c: Likewise. ++ * sysdeps/x86_64/tst-avxmod.c: Likewise. ++ * sysdeps/x86_64/tst-sse.c: Likewise. ++ * sysdeps/x86_64/tst-ssemod.c: Likewise. ++ ++2017-07-19 DJ Delorie ++ ++ [BZ #21654] ++ * grp/grp-merge.c (libc_hidden_def): Fix cast-after-dereference. ++ ++2017-07-14 DJ Delorie ++ ++ [BZ #21654] ++ * grp/grp_merge.c (__copy_grp): Align char** to minimum pointer ++ alignment not char alignment. ++ (__merge_grp): Likewise. ++ ++2017-08-22 Joseph Myers ++ ++ [BZ #21987] ++ * sysdeps/unix/sysv/linux/sparc/bits/long-double.h: Remove file ++ and copy to ... ++ * sysdeps/unix/sysv/linux/sparc/sparc32/bits/long-double.h: ++ ... here. ++ * sysdeps/unix/sysv/linux/sparc/sparc64/bits/long-double.h: ++ ... and here. ++ ++2017-09-11 H.J. Lu ++ Florian Weimer ++ ++ * configure.ac (find_cxx_header): Suppress compiler error message. ++ * configure: Regenerated. ++ ++ [BZ #21573] ++ * Makerules [$(c++-bits-std_abs-h) != ""] (before-compile): Add ++ $(common-objpfx)bits/std_abs.h. ++ [$(c++-bits-std_abs-h) != ""] ($(common-objpfx)bits/std_abs.h): ++ New target. ++ * config.make.in (c++-bits-std_abs-h): New. ++ * configure.ac (find_cxx_header): Use "\,$1," with sed. ++ (CXX_BITS_STD_ABS_H): New. ++ (AC_SUBST(CXX_BITS_STD_ABS_H)): Likewise. ++ * configure: Regenerated. ++ ++2017-09-11 H.J. Lu ++ ++ [BZ #21982] ++ * string/stratcliff.c (do_test): Declare size, nchars, inner, ++ middle and outer with size_t instead of int. Repleace %d and ++ %Zd with %zu in printf. Update "MAX (0, nchars - 128)" and ++ "MAX (outer, nchars - 64)" to support unsigned outer and ++ nchars. Also exit loop when outer == 0. ++ ++2017-09-07 H.J. Lu ++ ++ * resolv/tst-resolv-qtypes.c (domain): Changed to ++ "const char domain[] =". ++ ++2017-08-31 H.J. Lu ++ ++ [BZ #22051] ++ * Makerules (build-module-helper-objlist): Filter out ++ $(elf-objpfx)sofini.os. ++ (build-shlib-objlist): Append $(elf-objpfx)sofini.os if it is ++ needed. ++ ++2017-07-29 Torvald Riegel ++ Carlos O'Donell ++ ++ [BZ 21778] ++ * nptl/pthread_mutex_timedlock.c (__pthread_mutex_timedlock): Update ++ oldval if the CAS fails. ++ * nptl/pthread_mutex_lock.c (__pthread_mutex_lock_full): Likewise. ++ * nptl/tst-mutex7.c: Add comments explaining template test. ++ (ROBUST, DELAY_NSEC, ROUNDS, N): New. ++ (tf, do_test): Use them. ++ * nptl/tst-mutex7robust.c: New file. ++ * nptl/Makefile (tests): Add new test. ++ ++2017-07-28 Torvald Riegel ++ Carlos O'Donell ++ ++ [BZ #21298] ++ * nptl/Makefile (tests): Add tst-rwlock20. ++ * nptl/pthread_rwlock_common.c (__pthread_rwlock_rdlock_full): Fix ++ explicit hand-over. ++ (__pthread_rwlock_wrlock_full): Likewise. ++ * nptl/tst-rwlock20.c: New file. ++ ++2017-08-21 Florian Weimer ++ ++ [BZ #21972] ++ * assert/assert.h (assert): Use static_cast (bool) for C++. ++ Use the ternary operator in the warning branch for GNU C. ++ * assert/Makefile (tests): Add tst-assert-c++, tst-assert-g++. ++ (CFLAGS-tst-assert-c++.o): Compile in C++11 mode. ++ (CFLAGS-tst-assert-g++.o): Compile in GnU C++11 mode. ++ (LDLIBS-tst-assert-c++, LDLIBS-tst-assert-g++): Link with libstdc++. ++ * assert/tst-assert-c++.cc, assert/tst-assert-g++.cc: New files. ++ ++2017-04-13 Florian Weimer ++ ++ [BZ #21361] ++ Limit EDNS buffer size to 1200 bytes. ++ * include/resolv.h (__res_nopt): Remove declaration. ++ * resolv/Makefile (tests): tst-resolv-edns. ++ (tst-resolv-edns): Link with -lresolv, -lpthread. ++ * resolv/res_mkquery.c (__res_ntop): Limit EDNS buffer size to the ++ interval [512, 1200]. ++ * resolv/res_query.c (__libc_res_nquery): Use 1200 buffer size if ++ we can resize the buffer. ++ * resolv/resolv-internal.h (RESOLV_EDNS_BUFFER_SIZE): Define. ++ (__res_nopt): Declare. ++ * resolv/tst-resolv-edns.c: New file. ++ * resolv/resolv_test.h (struct resolv_edns_info): Define. ++ (struct resolv_response_context): Add edns member. ++ * resolv/resolv_test.c (struct query_info): Add edns member. ++ (parse_query): Extract EDNS information from the query. ++ (server_thread_udp_process_one): Propagate EDNS data. ++ (server_thread_tcp_client): Likewise. ++ ++2017-08-12 John David Anglin ++ ++ [BZ 19170] ++ * sysdeps/hppa/dl-trampoline.S (_dl_runtime_resolve): Return to caller ++ if _dl_fixup fails. ++ ++2017-08-12 John David Anglin ++ Adhemerval Zanella ++ ++ [BZ #21512] ++ * sysdeps/unix/sysv/linux/aarch64/clone.S (__clone): Call exit ++ syscall instead of jump to _exit. ++ * sysdeps/unix/sysv/linux/hppa/localplt.data: Remove _exit entry. ++ ++2017-08-12 Adhemerval Zanella ++ ++ * sysdeps/unix/sysv/linux/hppa/ipc_priv.h: New file. ++ ++2017-08-12 John David Anglin ++ ++ * sysdeps/unix/sysv/linux/hppa/clone.S (__clone): Add .cfi annotation. ++ * sysdeps/unix/sysv/linux/hppa/getcontext.S (__getcontext): Likewise. ++ * sysdeps/unix/sysv/linux/hppa/pt-vfork.S (__vfork): Likewise. ++ * sysdeps/unix/sysv/linux/hppa/setcontext.S (__setcontext): Likewise. ++ ++ * sysdeps/unix/sysv/linux/hppa/getcontext.S (__getcontext): Fix stack ++ offset for r19 load. ++ ++ * sysdeps/unix/sysv/linux/hppa/setcontext.S (__setcontext): Return 0. ++ ++ * sysdeps/unix/sysv/linux/hppa/sysdep-cancel.h (PSEUDO): Fix CFA offset. ++ Use .cfi_def_cfa_offset instead of .cfi_offset. Don't record stack ++ pointer offset. Correct PIC register offset. Don't mention frame ++ related instructions in epilogue. ++ (PUSHARGS_1): Correct offset. ++ (PUSHARGS_2): Likewise. ++ (PUSHARGS_3): Likewise. ++ (PUSHARGS_4): Likewise. ++ (PUSHARGS_5): Likewise. ++ (PUSHARGS_6): Likewise. ++ (POPARGS_1): Don't mention register restore. ++ (POPARGS_2): Likewise. ++ (POPARGS_3): Likewise. ++ (POPARGS_4): Likewise. ++ (POPARGS_5): Likewise. ++ (POPARGS_6): Likewise. ++ * sysdeps/unix/sysv/linux/hppa/sysdep.h (SAVE_PIC): Don't mention ++ copy of PIC register. ++ (LOAD_PIC): Likewise don't mention restore. ++ (DO_CALL): Fix CFA offset. Use .cfi_def_cfa_offset instead of ++ .cfi_offset. Don't record stack pointer offset. Correct PIC register ++ offset. Don't mention frame related instructions in epilogue. ++ ++ [BZ 20098] ++ * sysdeps/hppa/dl-fptr.c (_dl_read_access_allowed): New. ++ (_dl_lookup_address): Return address if it is not consistent with ++ being a linker defined function pointer. Likewise, return address ++ if address and function descriptor addresses are not accessible. ++ ++ [BZ locale/19838] ++ * sysdeps/unix/sysv/linux/hppa/bits/shm.h (SHMLBA): Set to page size. ++ ++ * nptl/allocatestack.c (allocate_stack): Align old and new guard ++ addresses to page boundaries when the stack grows up. ++ ++ * sysdeps/hppa/math-tests.h: New. ++ ++ [BZ #21016] ++ * sysdeps/hppa/nptl/bits/pthreadtypes.h: Update pthread_cond_t typedef. ++ * sysdeps/unix/sysv/linux/hppa/pthread.h: Include ++ bits/types/struct_timespec.h. ++ (PTHREAD_MUTEX_INITIALIZER): Revise define. ++ (PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP): Likewise. ++ (PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP): Likewise. ++ (PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP): Likewise. ++ (PTHREAD_RWLOCK_INITIALIZER): Likewise. ++ (PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP): Likewise. ++ (PTHREAD_COND_INITIALIZER): Likewise. ++ Remove old definitions. ++ * sysdeps/unix/sysv/linux/hppa/internaltypes.h: Delete. ++ * sysdeps/unix/sysv/linux/hppa/pthread_cond_broadcast.c: Delete. ++ * sysdeps/unix/sysv/linux/hppa/pthread_cond_destroy.c: Delete. ++ * sysdeps/unix/sysv/linux/hppa/pthread_cond_init.c: Delete. ++ * sysdeps/unix/sysv/linux/hppa/pthread_cond_signal.c: Delete. ++ * sysdeps/unix/sysv/linux/hppa/pthread_cond_wait.c: Delete. ++ ++2017-08-11 Florian Weimer ++ ++ [BZ #21242] ++ * assert/assert.h [__GNUC__ && !__STRICT_ANSI__] (assert): ++ Suppress pedantic warning resulting from statement expression. ++ (__ASSERT_FUNCTION): Add missing __extension__. ++ ++2017-08-08 Helge Deller ++ ++ [BZ #21049] ++ * sysdeps/hppa/__longjmp.c (__longjmp): Move call to CHECK_SP up ++ to avoid clobbering r26. ++ ++2017-08-06 H.J. Lu ++ ++ [BZ #21871] ++ * sysdeps/x86/cpu-features.c (init_cpu_features): Set ++ bit_arch_Use_dl_runtime_resolve_opt only with AVX512F. ++ ++2017-08-04 Aurelien Jarno ++ ++ * sysdeps/i386/i686/fpu/multiarch/libm-test-ulps: Regenerated. ++ ++2017-08-03 Aurelien Jarno ++ ++ * stdlib/getentropy.c (getentropy): Change return type to int. ++ ++2017-04-28 Tulio Magno Quites Machado Filho ++ ++ [BZ #21280] ++ * sysdeps/powerpc/power7/fpu/s_logbl.c (__logbl): Ignore the ++ signal of subnormals and adjust the exponent of power of 2 down ++ when low part has opposite sign. ++ ++2017-07-26 H.J. Lu ++ ++ [BZ #21666] ++ * misc/regexp.c (loc1): Add __attribute__ ((nocommon)); ++ (loc2): Likewise. ++ (locs): Likewise. ++ ++2017-07-12 Szabolcs Nagy ++ ++ * sysdeps/aarch64/dl-machine.h (RTLD_START_1): Change _dl_argv to the ++ hidden __GI__dl_argv symbol. ++ ++2017-07-06 Florian Weimer ++ H.J. Lu ++ ++ [BZ #21609] ++ * sysdeps/x86_64/Makefile (sysdep-dl-routines): Add tls_get_addr. ++ (gen-as-const-headers): Add rtld-offsets.sym. ++ * sysdeps/x86_64/dl-tls.c: New file. ++ * sysdeps/x86_64/rtld-offsets.sym: Likwise. ++ * sysdeps/x86_64/tls_get_addr.S: Likewise. ++ * sysdeps/x86_64/dl-tls.h: Add multiple inclusion guards. ++ * sysdeps/x86_64/tlsdesc.sym (TI_MODULE_OFFSET): New. ++ (TI_OFFSET_OFFSET): Likwise. ++ ++2017-06-14 Florian Weimer ++ ++ * sysdeps/i386/i686/multiarch/strcspn-c.c: Add IS_IN (libc) guard. ++ * sysdeps/i386/i686/multiarch/varshift.c: Likewise. ++ ++2017-03-07 Siddhesh Poyarekar ++ ++ [BZ #21209] ++ * elf/rtld.c (process_envvars): Ignore LD_HWCAP_MASK for ++ AT_SECURE processes. ++ * sysdeps/generic/unsecvars.h: Add LD_HWCAP_MASK. ++ * elf/tst-env-setuid.c (test_parent): Test LD_HWCAP_MASK. ++ (test_child): Likewise. ++ * elf/Makefile (tst-env-setuid-ENV): Add LD_HWCAP_MASK. ++ ++2017-06-19 Florian Weimer ++ ++ * elf/rtld.c (audit_list_string): New variable. ++ (audit_list): Update comment. ++ (struct audit_list_iter): Define. ++ (audit_list_iter_init, audit_list_iter_next): New function. ++ (dl_main): Use struct audit_list_iter to process audit modules. ++ (process_dl_audit): Call dso_name_valid_for_suid. ++ (process_envvars): Set audit_list_string instead of calling ++ process_dl_audit. ++ ++2017-06-19 Florian Weimer ++ ++ * elf/rtld.c (SECURE_NAME_LIMIT, SECURE_PATH_LIMIT): Define. ++ (dso_name_valid_for_suid): New function. ++ (handle_ld_preload): Likewise. ++ (dl_main): Call it. Remove alloca. ++ ++2017-06-19 Florian Weimer ++ ++ [BZ #21624] ++ CVE-2017-1000366 ++ * elf/rtld.c (process_envvars): Ignore LD_LIBRARY_PATH for ++ __libc_enable_secure. ++ ++2017-05-12 Florian Weimer ++ ++ [BZ #21386] ++ * sysdeps/nptl/fork.c (__libc_fork): Remove assertions on the ++ parent PID. The assertion in the child is incorrect with PID ++ namespaces. ++ ++2017-03-15 Joseph Myers ++ ++ * sysdeps/x86/fpu/test-math-vector-sincos.h (INIT_VEC_PTRS_LOOP): ++ Use a union when storing pointers. ++ (VECTOR_WRAPPER_fFF_2): Do not take address of integer vector and ++ cast result when passing to INIT_VEC_PTRS_LOOP. ++ (VECTOR_WRAPPER_fFF_3): Likewise. ++ (VECTOR_WRAPPER_fFF_4): Likewise. ++ ++2017-05-01 Adhemerval Zanella ++ ++ [BZ# 21182] ++ * string/test-memchr.c (do_test): Add BZ#21182 checks for address ++ near end of a page. ++ * sysdeps/i386/i686/multiarch/memchr-sse2.S (__memchr): Fix ++ overflow calculation. ++ ++2017-04-28 H.J. Lu ++ ++ [BZ #21396] ++ * sysdeps/x86/cpu-features.c (init_cpu_features): Set ++ Prefer_No_AVX512 if AVX512ER isn't available. ++ * sysdeps/x86/cpu-features.h (bit_arch_Prefer_No_AVX512): New. ++ (index_arch_Prefer_No_AVX512): Likewise. ++ * sysdeps/x86_64/multiarch/memcpy.S (__new_memcpy): Don't use ++ AVX512 version if Prefer_No_AVX512 is set. ++ * sysdeps/x86_64/multiarch/memcpy_chk.S (__memcpy_chk): ++ Likewise. ++ * sysdeps/x86_64/multiarch/memmove.S (__libc_memmove): Likewise. ++ * sysdeps/x86_64/multiarch/memmove_chk.S (__memmove_chk): ++ Likewise. ++ * sysdeps/x86_64/multiarch/mempcpy.S (__mempcpy): Likewise. ++ * sysdeps/x86_64/multiarch/mempcpy_chk.S (__mempcpy_chk): ++ Likewise. ++ * sysdeps/x86_64/multiarch/memset.S (memset): Likewise. ++ * sysdeps/x86_64/multiarch/memset_chk.S (__memset_chk): ++ Likewise. ++ ++2017-04-28 H.J. Lu ++ ++ * sysdeps/x86/cpu-features.c (init_cpu_features): Set ++ Prefer_No_VZEROUPPER if AVX512ER is available. ++ * sysdeps/x86/cpu-features.h ++ (bit_cpu_AVX512PF): New. ++ (bit_cpu_AVX512ER): Likewise. ++ (bit_cpu_AVX512CD): Likewise. ++ (bit_cpu_AVX512BW): Likewise. ++ (bit_cpu_AVX512VL): Likewise. ++ (index_cpu_AVX512PF): Likewise. ++ (index_cpu_AVX512ER): Likewise. ++ (index_cpu_AVX512CD): Likewise. ++ (index_cpu_AVX512BW): Likewise. ++ (index_cpu_AVX512VL): Likewise. ++ (reg_AVX512PF): Likewise. ++ (reg_AVX512ER): Likewise. ++ (reg_AVX512CD): Likewise. ++ (reg_AVX512BW): Likewise. ++ (reg_AVX512VL): Likewise. ++ ++2017-04-11 Adhemerval Zanella ++ ++ * posix/globtest.sh: Add cleanup routine on trap 0. ++ ++2017-04-07 H.J. Lu ++ ++ [BZ #21258] ++ * sysdeps/x86_64/dl-trampoline.S (_dl_runtime_resolve_opt): ++ Define only if _dl_runtime_resolve is defined to ++ _dl_runtime_resolve_sse_vex. ++ * sysdeps/x86_64/dl-trampoline.h (_dl_runtime_resolve_opt): ++ Fallthrough to _dl_runtime_resolve_sse_vex. ++ ++2017-04-03 Mike Frysinger ++ ++ [BZ #21253] ++ * sysdeps/unix/sysv/linux/spawni.c (__spawnix): Increase argv_size ++ slack space by 32KiB. ++ ++2017-04-03 Wladimir van der Laan ++ ++ [BZ# 21338] ++ * malloc/malloc.c: Call do_set_arena_max for M_ARENA_MAX ++ instead of incorrect do_set_arena_test ++ ++2017-03-31 Slava Barinov ++ ++ [BZ #21289] ++ * io/fts.h (fts_set): Replace __REDIRECT with __REDIRECT_NTH. ++ ++2017-03-20 Mike Frysinger ++ ++ [BZ #21275] ++ * sysdeps/unix/sysv/linux/spawni.c [__ia64__] (CLONE): Rename ++ __stack to __stackbase. ++ (STACK): Invert _STACK_GROWS_DOWN and _STACK_GROWS_UP order of ++ checks so we can include defined(__ia64__) first. ++ ++2017-03-15 Mike Frysinger ++ ++ * sysdeps/x86_64/mempcpy_chk.S (__mempcpy_chk): Check for SHARED ++ instead of PIC. ++ ++2017-03-15 John David Anglin ++ ++ * sysdeps/hppa/dl-machine.h (DL_STACK_END): Define. ++ (RTLD_START): Don't record stack end address in _dl_start_user. ++ ++2017-03-02 Florian Weimer ++ ++ [BZ #21015] ++ * manual/install.texi (Configuring and compiling): Document ++ --enable-bind-now. ++ * Makeconfig [bind-now] (LDFLAGS-lib.so): Set. ++ (build-shlib-helper): Use $(LDFLAGS-lib.so). ++ (format.lds): Likewise. ++ [bind-now] (LDFLAGS-c.so): Remove. ++ * sysdeps/x86_64/localplt.data (libm.so): matherr relocation can ++ be R_X86_64_GLOB_DAT. ++ * sysdeps/unix/sysv/linux/i386/localplt.data (libm.so): matherr ++ relocation can be R_386_GLOB_DAT. ++ * sysdeps/unix/sysv/linux/alpha/localplt.data (libm.so): matherr ++ relocaiton can be R_ALPHA_GLOB_DAT. ++ * iconvdata/Makefile [bind-now] (LDFLAGS.so): Add -Wl,-z,now. ++ ++2017-02-28 Florian Weimer ++ ++ [BZ #20257] ++ * inet/Makefile (routines): Add deadline. ++ (tests-static): Add tst-deadline. ++ * inet/net-internal.h (struct deadline_current_time) ++ (__deadline_current_time, struct deadline, __deadline_is_infinite) ++ (__deadline_elapsed, __deadline_first, __deadline_from_timeval) ++ (__deadline_to_ms, __is_timeval_valid_timeout): Declare. ++ * inet/deadline.c: New file. ++ * inet/tst-deadline.c: Likewise. ++ * sunrpc/Makefile (tests): Add tst-udp-nonblocking, ++ tst-udp-timeout, tst-udp-garbage. ++ (tst-udp-nonblocking, tst-udp-timeout): Link against libc.so ++ explicitly. ++ (tst-udp-garbage): Likewise. Also link against thread library. ++ * sunrpc/clnt_udp.c (struct cu_data): Mention in comment that the ++ struct layout is part of the ABI. ++ (clntudp_call): Rework timeout handling. ++ * sunrpc/tst-udp-garbage.c: New file. ++ * sunrpc/tst-udp-nonblocking.c: Likewise. ++ * sunrpc/tst-udp-timeout.c: Likewise. ++ ++2017-02-27 Florian Weimer ++ ++ [BZ #21115] ++ * sunrpc/clnt_udp.c (clntudp_call): Free ancillary data later. ++ * sunrpc/Makefile (tests): Add tst-udp-error. ++ (tst-udp-error): Link against libc.so explicitly. ++ * sunrpc/tst-udp-error: New file. ++ ++2017-02-08 Siddhesh Poyarekar ++ ++ [BZ #21109] ++ * elf/dl-tunable-types.h (tunable_callback_t): Accept ++ tunable_val_t as argument. ++ * elf/dl-tunables.c (__tunable_set_val): Add comment. ++ * malloc/arena.c (set_mallopt_check): Take tunable_val_t as ++ argument. ++ (DL_TUNABLE_CALLBACK_FNDECL): Likewise. ++ + 2017-02-05 Siddhesh Poyarekar + + * version.h (RELEASE): Set to "stable" +diff --git a/INSTALL b/INSTALL +index 3b3fd121b2..e77cb2d4e2 100644 +--- a/INSTALL ++++ b/INSTALL +@@ -146,6 +146,12 @@ will be used, and CFLAGS sets optimization options for the compiler. + of routines called directly from assembler are excluded from this + protection. + ++'--enable-bind-now' ++ Disable lazy binding for installed shared objects. This provides ++ additional security hardening because it enables full RELRO and a ++ read-only global offset table (GOT), at the cost of slightly ++ increased program load times. ++ + '--enable-pt_chown' + The file 'pt_chown' is a helper binary for 'grantpt' (*note + Pseudo-Terminals: Allocation.) that is installed setuid root to fix +diff --git a/Makeconfig b/Makeconfig +index 97a15b569e..1c815113b9 100644 +--- a/Makeconfig ++++ b/Makeconfig +@@ -386,6 +386,13 @@ LDFLAGS.so += $(hashstyle-LDFLAGS) + LDFLAGS-rtld += $(hashstyle-LDFLAGS) + endif + ++# If lazy relocations are disabled, add the -z now flag. Use ++# LDFLAGS-lib.so instead of LDFLAGS.so, to avoid adding the flag to ++# test modules. ++ifeq ($(bind-now),yes) ++LDFLAGS-lib.so += -Wl,-z,now ++endif ++ + # Command to run after every final link (executable or shared object). + # This is invoked with $(call after-link,...), so it should operate on + # the file $1. This can be set to do some sort of post-processing on +diff --git a/Makerules b/Makerules +index e9194e54cf..43343f03ee 100644 +--- a/Makerules ++++ b/Makerules +@@ -127,6 +127,14 @@ $(common-objpfx)cstdlib: $(c++-cstdlib-header) + $(common-objpfx)cmath: $(c++-cmath-header) + $(INSTALL_DATA) $< $@T + $(move-if-change) $@T $@ ++ifneq (,$(c++-bits-std_abs-h)) ++# Also make a copy of from GCC 7 to prevent it from ++# including /usr/include/stdlib.h. ++before-compile := $(common-objpfx)bits/std_abs.h $(before-compile) ++$(common-objpfx)bits/std_abs.h: $(c++-bits-std_abs-h) ++ $(INSTALL_DATA) $< $@T ++ $(move-if-change) $@T $@ ++endif + endif + + before-compile := $(common-objpfx)libc-abis.h $(before-compile) +@@ -588,7 +596,7 @@ $(LINK.o) -shared -static-libgcc -Wl,-O1 $(sysdep-LDFLAGS) \ + $(extra-B-$(@F:lib%.so=%).so) -B$(csu-objpfx) \ + $(extra-B-$(@F:lib%.so=%).so) $(load-map-file) \ + -Wl,-soname=lib$(libprefix)$(@F:lib%.so=%).so$($(@F)-version) \ +- $(LDFLAGS.so) $(LDFLAGS-$(@F:lib%.so=%).so) \ ++ $(LDFLAGS.so) $(LDFLAGS-lib.so) $(LDFLAGS-$(@F:lib%.so=%).so) \ + -L$(subst :, -L,$(rpath-link)) -Wl,-rpath-link=$(rpath-link) + endef + +@@ -669,14 +677,17 @@ $(build-module-helper) -o $@ $(shlib-lds-flags) \ + $(call after-link,$@) + endef + ++# sofini.os must be placed last since it terminates .eh_frame section. + build-module-helper-objlist = \ + $(patsubst %_pic.a,$(whole-archive) %_pic.a $(no-whole-archive),\ + $(filter-out %.lds $(map-file) $(+preinit) $(+postinit) \ ++ $(elf-objpfx)sofini.os \ + $(link-libc-deps),$^)) + + build-module-objlist = $(build-module-helper-objlist) $(LDLIBS-$(@F:%.so=%).so) + build-shlib-objlist = $(build-module-helper-objlist) \ +- $(LDLIBS-$(@F:lib%.so=%).so) ++ $(LDLIBS-$(@F:lib%.so=%).so) \ ++ $(filter $(elf-objpfx)sofini.os,$^) + + # Don't try to use -lc when making libc.so itself. + # Also omits crti.o and crtn.o, which we do not want +@@ -686,10 +697,6 @@ LDFLAGS-c.so = -nostdlib -nostartfiles + LDLIBS-c.so += $(libc.so-gnulib) + # Give libc.so an entry point and make it directly runnable itself. + LDFLAGS-c.so += -e __libc_main +-# If lazy relocation is disabled add the -z now flag. +-ifeq ($(bind-now),yes) +-LDFLAGS-c.so += -Wl,-z,now +-endif + # Pre-link the objects of libc_pic.a so that we can locally resolve + # COMMON symbols before we link against ld.so. This is because ld.so + # contains some of libc_pic.a already, which will prevent the COMMONs +@@ -1104,7 +1111,8 @@ $(common-objpfx)format.lds: $(..)scripts/output-format.sed \ + ifneq (unknown,$(output-format)) + echo > $@.new 'OUTPUT_FORMAT($(output-format))' + else +- $(LINK.o) -shared $(sysdep-LDFLAGS) $(rtld-LDFLAGS) $(LDFLAGS.so) \ ++ $(LINK.o) -shared $(sysdep-LDFLAGS) $(rtld-LDFLAGS) \ ++ $(LDFLAGS.so) $(LDFLAGS-lib.so) \ + -x c /dev/null -o $@.so -Wl,--verbose -v 2>&1 \ + | sed -n -f $< > $@.new + test -s $@.new +diff --git a/NEWS b/NEWS +index ec15dde761..7c44ba2a8a 100644 +--- a/NEWS ++++ b/NEWS +@@ -5,6 +5,60 @@ See the end for copying conditions. + Please send GNU C library bug reports via + using `glibc' in the "product" field. + ++Version 2.25.1 ++ ++Security related changes: ++ ++* The DNS stub resolver limits the advertised UDP buffer size to 1200 bytes, ++ to avoid fragmentation-based spoofing attacks. ++ ++ CVE-2017-15670: The glob function, when invoked with GLOB_TILDE, suffered ++ from a one-byte overflow during ~ operator processing (either on the stack ++ or the heap, depending on the length of the user name). ++ ++ CVE-2017-15671: The glob function, when invoked with GLOB_TILDE, ++ would sometimes fail to free memory allocated during ~ operator ++ processing, leading to a memory leak and, potentially, to a denial ++ of service. ++ ++ CVE-2017-15804: The glob function, when invoked with GLOB_TILDE and ++ without GLOB_NOESCAPE, could write past the end of a buffer while ++ unescaping user names. Reported by Tim Rühsen. ++ ++ CVE-2017-1000408: Incorrect array size computation in _dl_init_paths leads ++ to the allocation of too much memory. (This is not a security bug per se, ++ it is mentioned here only because of the CVE assignment.) Reported by ++ Qualys. ++ ++ CVE-2017-1000409: Buffer overflow in _dl_init_paths due to miscomputation ++ of the number of search path components. (This is not a security ++ vulnerability per se because no trust boundary is crossed if the fix for ++ CVE-2017-1000366 has been applied, but it is mentioned here only because ++ of the CVE assignment.) Reported by Qualys. ++ ++ CVE-2017-16997: Incorrect handling of RPATH or RUNPATH containing $ORIGIN ++ for AT_SECURE or SUID binaries could be used to load libraries from the ++ current directory. ++ ++The following bugs are resolved with this release: ++ ++ [20257] sunrpc: clntudp_call does not enforce timeout when receiving data ++ [21015] Document and fix --enable-bind-now ++ [21109] Tunables broken on big-endian ++ [21115] sunrpc: Use-after-free in error path in clntudp_call ++ [21209] Ignore and remove LD_HWCAP_MASK for AT_SECURE programs ++ [21242] assert: Suppress pedantic warning caused by statement expression ++ [21265] x86-64: Use fxsave/xsave/xsavec in _dl_runtime_resolve ++ [21289] Fix symbol redirect for fts_set ++ [21298] rwlock can deadlock on frequent reader/writer phase switching ++ [21386] Assertion in fork for distinct parent PID is incorrect ++ [21624] Unsafe alloca allows local attackers to alias stack and heap (CVE-2017-1000366) ++ [21654] nss: Fix invalid cast in group merging ++ [21778] Robust mutex may deadlock ++ [21972] assert macro requires operator== (int) for its argument type ++ [22322] libc: [mips64] wrong bits/long-double.h installed ++ [22627] $ORIGIN in $LD_LIBRARY_PATH is substituted twice ++ + Version 2.25 + + * The feature test macro __STDC_WANT_LIB_EXT2__, from ISO/IEC TR +diff --git a/assert/Makefile b/assert/Makefile +index 1c3be9b01f..9ec1be81a9 100644 +--- a/assert/Makefile ++++ b/assert/Makefile +@@ -25,6 +25,15 @@ include ../Makeconfig + headers := assert.h + + routines := assert assert-perr __assert +-tests := test-assert test-assert-perr ++tests := test-assert test-assert-perr tst-assert-c++ tst-assert-g++ + + include ../Rules ++ ++ifeq ($(have-cxx-thread_local),yes) ++CFLAGS-tst-assert-c++.o = -std=c++11 ++LDLIBS-tst-assert-c++ = -lstdc++ ++CFLAGS-tst-assert-g++.o = -std=gnu++11 ++LDLIBS-tst-assert-g++ = -lstdc++ ++else ++tests-unsupported += tst-assert-c++ tst-assert-g++ ++endif +diff --git a/assert/assert.h b/assert/assert.h +index 22f019537c..640c95c063 100644 +--- a/assert/assert.h ++++ b/assert/assert.h +@@ -85,19 +85,29 @@ __END_DECLS + /* When possible, define assert so that it does not add extra + parentheses around EXPR. Otherwise, those added parentheses would + suppress warnings we'd expect to be detected by gcc's -Wparentheses. */ +-# if !defined __GNUC__ || defined __STRICT_ANSI__ ++# if defined __cplusplus ++# define assert(expr) \ ++ (static_cast (expr) \ ++ ? void (0) \ ++ : __assert_fail (#expr, __FILE__, __LINE__, __ASSERT_FUNCTION)) ++# elif !defined __GNUC__ || defined __STRICT_ANSI__ + # define assert(expr) \ + ((expr) \ + ? __ASSERT_VOID_CAST (0) \ + : __assert_fail (#expr, __FILE__, __LINE__, __ASSERT_FUNCTION)) + # else ++/* The first occurrence of EXPR is not evaluated due to the sizeof, ++ but will trigger any pedantic warnings masked by the __extension__ ++ for the second occurrence. The ternary operator is required to ++ support function pointers and bit fields in this context, and to ++ suppress the evaluation of variable length arrays. */ + # define assert(expr) \ +- ({ \ ++ ((void) sizeof ((expr) ? 1 : 0), __extension__ ({ \ + if (expr) \ + ; /* empty */ \ + else \ + __assert_fail (#expr, __FILE__, __LINE__, __ASSERT_FUNCTION); \ +- }) ++ })) + # endif + + # ifdef __USE_GNU +@@ -113,7 +123,7 @@ __END_DECLS + C9x has a similar variable called __func__, but prefer the GCC one since + it demangles C++ function names. */ + # if defined __cplusplus ? __GNUC_PREREQ (2, 6) : __GNUC_PREREQ (2, 4) +-# define __ASSERT_FUNCTION __PRETTY_FUNCTION__ ++# define __ASSERT_FUNCTION __extension__ __PRETTY_FUNCTION__ + # else + # if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L + # define __ASSERT_FUNCTION __func__ +diff --git a/assert/tst-assert-c++.cc b/assert/tst-assert-c++.cc +new file mode 100644 +index 0000000000..12a5e690cb +--- /dev/null ++++ b/assert/tst-assert-c++.cc +@@ -0,0 +1,78 @@ ++/* Tests for interactions between C++ and assert. ++ Copyright (C) 2017 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 ++ . */ ++ ++#include ++ ++/* The C++ standard requires that if the assert argument is a constant ++ subexpression, then the assert itself is one, too. */ ++constexpr int ++check_constexpr () ++{ ++ return (assert (true), 1); ++} ++ ++/* Objects of this class can be contextually converted to bool, but ++ cannot be compared to int. */ ++struct no_int ++{ ++ no_int () = default; ++ no_int (const no_int &) = delete; ++ ++ explicit operator bool () const ++ { ++ return true; ++ } ++ ++ bool operator! () const; /* No definition. */ ++ template bool operator== (T) const; /* No definition. */ ++ template bool operator!= (T) const; /* No definition. */ ++}; ++ ++/* This class tests that operator== is not used by assert. */ ++struct bool_and_int ++{ ++ bool_and_int () = default; ++ bool_and_int (const no_int &) = delete; ++ ++ explicit operator bool () const ++ { ++ return true; ++ } ++ ++ bool operator! () const; /* No definition. */ ++ template bool operator== (T) const; /* No definition. */ ++ template bool operator!= (T) const; /* No definition. */ ++}; ++ ++static int ++do_test () ++{ ++ { ++ no_int value; ++ assert (value); ++ } ++ ++ { ++ bool_and_int value; ++ assert (value); ++ } ++ ++ return 0; ++} ++ ++#include +diff --git a/assert/tst-assert-g++.cc b/assert/tst-assert-g++.cc +new file mode 100644 +index 0000000000..8c06402825 +--- /dev/null ++++ b/assert/tst-assert-g++.cc +@@ -0,0 +1,19 @@ ++/* Tests for interactions between C++ and assert. GNU C++11 version. ++ Copyright (C) 2017 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 ++ . */ ++ ++#include +diff --git a/config.make.in b/config.make.in +index 5836b32a72..709527da4f 100644 +--- a/config.make.in ++++ b/config.make.in +@@ -47,6 +47,7 @@ sysincludes = @SYSINCLUDES@ + c++-sysincludes = @CXX_SYSINCLUDES@ + c++-cstdlib-header = @CXX_CSTDLIB_HEADER@ + c++-cmath-header = @CXX_CMATH_HEADER@ ++c++-bits-std_abs-h = @CXX_BITS_STD_ABS_H@ + all-warnings = @all_warnings@ + enable-werror = @enable_werror@ + +diff --git a/configure b/configure +index eecd0ace74..ee637a7caf 100755 +--- a/configure ++++ b/configure +@@ -634,6 +634,7 @@ BISON + INSTALL_INFO + PERL + BASH_SHELL ++CXX_BITS_STD_ABS_H + CXX_CMATH_HEADER + CXX_CSTDLIB_HEADER + CXX_SYSINCLUDES +@@ -5318,14 +5319,17 @@ fi + # copy of those headers in Makerules. + if test -n "$CXX"; then + find_cxx_header () { +- echo "#include <$1>" | $CXX -M -MP -x c++ - | sed -n "/$1:/{s/:\$//;p}" ++ echo "#include <$1>" | $CXX -M -MP -x c++ - 2>/dev/null \ ++ | sed -n "\,$1:,{s/:\$//;p}" + } + CXX_CSTDLIB_HEADER="$(find_cxx_header cstdlib)" + CXX_CMATH_HEADER="$(find_cxx_header cmath)" ++ CXX_BITS_STD_ABS_H="$(find_cxx_header bits/std_abs.h)" + fi + + + ++ + # Test if LD_LIBRARY_PATH contains the notation for the current directory + # since this would lead to problems installing/building glibc. + # LD_LIBRARY_PATH contains the current directory if one of the following +diff --git a/configure.ac b/configure.ac +index 4a77411b71..d288ff43cd 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1176,13 +1176,16 @@ AC_SUBST(CXX_SYSINCLUDES) + # copy of those headers in Makerules. + if test -n "$CXX"; then + find_cxx_header () { +- echo "#include <$1>" | $CXX -M -MP -x c++ - | sed -n "/$1:/{s/:\$//;p}" ++ echo "#include <$1>" | $CXX -M -MP -x c++ - 2>/dev/null \ ++ | sed -n "\,$1:,{s/:\$//;p}" + } + CXX_CSTDLIB_HEADER="$(find_cxx_header cstdlib)" + CXX_CMATH_HEADER="$(find_cxx_header cmath)" ++ CXX_BITS_STD_ABS_H="$(find_cxx_header bits/std_abs.h)" + fi + AC_SUBST(CXX_CSTDLIB_HEADER) + AC_SUBST(CXX_CMATH_HEADER) ++AC_SUBST(CXX_BITS_STD_ABS_H) + + # Test if LD_LIBRARY_PATH contains the notation for the current directory + # since this would lead to problems installing/building glibc. +diff --git a/elf/Makefile b/elf/Makefile +index 61abeb59ee..cc4aeb25b6 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -1398,6 +1398,7 @@ $(objpfx)tst-nodelete-dlclose: $(objpfx)tst-nodelete-dlclose-dso.so + $(objpfx)tst-nodelete-dlclose.out: $(objpfx)tst-nodelete-dlclose-dso.so \ + $(objpfx)tst-nodelete-dlclose-plugin.so + +-tst-env-setuid-ENV = MALLOC_CHECK_=2 MALLOC_MMAP_THRESHOLD_=4096 ++tst-env-setuid-ENV = MALLOC_CHECK_=2 MALLOC_MMAP_THRESHOLD_=4096 \ ++ LD_HWCAP_MASK=0xffffffff + tst-env-setuid-tunables-ENV = \ + GLIBC_TUNABLES=glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096 +diff --git a/elf/dl-load.c b/elf/dl-load.c +index a5318f9c8d..58e7220050 100644 +--- a/elf/dl-load.c ++++ b/elf/dl-load.c +@@ -37,6 +37,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -103,7 +104,9 @@ static size_t ncapstr attribute_relro; + static size_t max_capstrlen attribute_relro; + + +-/* Get the generated information about the trusted directories. */ ++/* Get the generated information about the trusted directories. Use ++ an array of concatenated strings to avoid relocations. See ++ gen-trusted-dirs.awk. */ + #include "trusted-dirs.h" + + static const char system_dirs[] = SYSTEM_DIRS; +@@ -111,9 +114,7 @@ static const size_t system_dirs_len[] = + { + SYSTEM_DIRS_LEN + }; +-#define nsystem_dirs_len \ +- (sizeof (system_dirs_len) / sizeof (system_dirs_len[0])) +- ++#define nsystem_dirs_len array_length (system_dirs_len) + + static bool + is_trusted_path (const char *path, size_t len) +@@ -433,31 +434,40 @@ fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep, + { + char *cp; + size_t nelems = 0; +- char *to_free; + + while ((cp = __strsep (&rpath, sep)) != NULL) + { + struct r_search_path_elem *dirp; ++ char *to_free = NULL; ++ size_t len = 0; + +- to_free = cp = expand_dynamic_string_token (l, cp, 1); ++ /* `strsep' can pass an empty string. */ ++ if (*cp != '\0') ++ { ++ to_free = cp = expand_dynamic_string_token (l, cp, 1); + +- size_t len = strlen (cp); ++ /* expand_dynamic_string_token can return NULL in case of empty ++ path or memory allocation failure. */ ++ if (cp == NULL) ++ continue; + +- /* `strsep' can pass an empty string. This has to be +- interpreted as `use the current directory'. */ +- if (len == 0) +- { +- static const char curwd[] = "./"; +- cp = (char *) curwd; +- } ++ /* Compute the length after dynamic string token expansion and ++ ignore empty paths. */ ++ len = strlen (cp); ++ if (len == 0) ++ { ++ free (to_free); ++ continue; ++ } + +- /* Remove trailing slashes (except for "/"). */ +- while (len > 1 && cp[len - 1] == '/') +- --len; ++ /* Remove trailing slashes (except for "/"). */ ++ while (len > 1 && cp[len - 1] == '/') ++ --len; + +- /* Now add one if there is none so far. */ +- if (len > 0 && cp[len - 1] != '/') +- cp[len++] = '/'; ++ /* Now add one if there is none so far. */ ++ if (len > 0 && cp[len - 1] != '/') ++ cp[len++] = '/'; ++ } + + /* Make sure we don't use untrusted directories if we run SUID. */ + if (__glibc_unlikely (check_trusted) && !is_trusted_path (cp, len)) +@@ -621,6 +631,14 @@ decompose_rpath (struct r_search_path_struct *sps, + necessary. */ + free (copy); + ++ /* There is no path after expansion. */ ++ if (result[0] == NULL) ++ { ++ free (result); ++ sps->dirs = (struct r_search_path_elem **) -1; ++ return false; ++ } ++ + sps->dirs = result; + /* The caller will change this value if we haven't used a real malloc. */ + sps->malloced = 1; +@@ -688,9 +706,8 @@ _dl_init_paths (const char *llp) + + ncapstr * sizeof (enum r_dir_status)) + / sizeof (struct r_search_path_elem)); + +- rtld_search_dirs.dirs[0] = (struct r_search_path_elem *) +- malloc ((sizeof (system_dirs) / sizeof (system_dirs[0])) +- * round_size * sizeof (struct r_search_path_elem)); ++ rtld_search_dirs.dirs[0] = malloc (nsystem_dirs_len * round_size ++ * sizeof (*rtld_search_dirs.dirs[0])); + if (rtld_search_dirs.dirs[0] == NULL) + { + errstring = N_("cannot create cache for search path"); +@@ -776,37 +793,14 @@ _dl_init_paths (const char *llp) + + if (llp != NULL && *llp != '\0') + { +- size_t nllp; +- const char *cp = llp; +- char *llp_tmp; +- +-#ifdef SHARED +- /* Expand DSTs. */ +- size_t cnt = DL_DST_COUNT (llp, 1); +- if (__glibc_likely (cnt == 0)) +- llp_tmp = strdupa (llp); +- else +- { +- /* Determine the length of the substituted string. */ +- size_t total = DL_DST_REQUIRED (l, llp, strlen (llp), cnt); +- +- /* Allocate the necessary memory. */ +- llp_tmp = (char *) alloca (total + 1); +- llp_tmp = _dl_dst_substitute (l, llp, llp_tmp, 1); +- } +-#else +- llp_tmp = strdupa (llp); +-#endif ++ char *llp_tmp = strdupa (llp); + + /* Decompose the LD_LIBRARY_PATH contents. First determine how many + elements it has. */ +- nllp = 1; +- while (*cp) +- { +- if (*cp == ':' || *cp == ';') +- ++nllp; +- ++cp; +- } ++ size_t nllp = 1; ++ for (const char *cp = llp_tmp; *cp != '\0'; ++cp) ++ if (*cp == ':' || *cp == ';') ++ ++nllp; + + env_path_list.dirs = (struct r_search_path_elem **) + malloc ((nllp + 1) * sizeof (struct r_search_path_elem *)); +diff --git a/elf/dl-tunable-types.h b/elf/dl-tunable-types.h +index a986f0b593..37a4e8021f 100644 +--- a/elf/dl-tunable-types.h ++++ b/elf/dl-tunable-types.h +@@ -21,8 +21,6 @@ + # define _TUNABLE_TYPES_H_ + #include + +-typedef void (*tunable_callback_t) (void *); +- + typedef enum + { + TUNABLE_TYPE_INT_32, +@@ -43,6 +41,8 @@ typedef union + const char *strval; + } tunable_val_t; + ++typedef void (*tunable_callback_t) (tunable_val_t *); ++ + /* Security level for tunables. This decides what to do with individual + tunables for AT_SECURE binaries. */ + typedef enum +diff --git a/elf/dl-tunables.c b/elf/dl-tunables.c +index a8d53d6a31..e42aa67003 100644 +--- a/elf/dl-tunables.c ++++ b/elf/dl-tunables.c +@@ -455,6 +455,8 @@ __tunable_set_val (tunable_id_t id, void *valp, tunable_callback_t callback) + if (cur->strval == NULL) + return; + ++ /* Caller does not need the value, just call the callback with our tunable ++ value. */ + if (valp == NULL) + goto cb; + +diff --git a/elf/rtld.c b/elf/rtld.c +index a036ece956..9362a21e73 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -99,14 +99,121 @@ uintptr_t __pointer_chk_guard_local + strong_alias (__pointer_chk_guard_local, __pointer_chk_guard) + #endif + ++/* Length limits for names and paths, to protect the dynamic linker, ++ particularly when __libc_enable_secure is active. */ ++#ifdef NAME_MAX ++# define SECURE_NAME_LIMIT NAME_MAX ++#else ++# define SECURE_NAME_LIMIT 255 ++#endif ++#ifdef PATH_MAX ++# define SECURE_PATH_LIMIT PATH_MAX ++#else ++# define SECURE_PATH_LIMIT 1024 ++#endif ++ ++/* Check that AT_SECURE=0, or that the passed name does not contain ++ directories and is not overly long. Reject empty names ++ unconditionally. */ ++static bool ++dso_name_valid_for_suid (const char *p) ++{ ++ if (__glibc_unlikely (__libc_enable_secure)) ++ { ++ /* Ignore pathnames with directories for AT_SECURE=1 ++ programs, and also skip overlong names. */ ++ size_t len = strlen (p); ++ if (len >= SECURE_NAME_LIMIT || memchr (p, '/', len) != NULL) ++ return false; ++ } ++ return *p != '\0'; ++} + +-/* List of auditing DSOs. */ ++/* LD_AUDIT variable contents. Must be processed before the ++ audit_list below. */ ++const char *audit_list_string; ++ ++/* Cyclic list of auditing DSOs. audit_list->next is the first ++ element. */ + static struct audit_list + { + const char *name; + struct audit_list *next; + } *audit_list; + ++/* Iterator for audit_list_string followed by audit_list. */ ++struct audit_list_iter ++{ ++ /* Tail of audit_list_string still needing processing, or NULL. */ ++ const char *audit_list_tail; ++ ++ /* The list element returned in the previous iteration. NULL before ++ the first element. */ ++ struct audit_list *previous; ++ ++ /* Scratch buffer for returning a name which is part of ++ audit_list_string. */ ++ char fname[SECURE_NAME_LIMIT]; ++}; ++ ++/* Initialize an audit list iterator. */ ++static void ++audit_list_iter_init (struct audit_list_iter *iter) ++{ ++ iter->audit_list_tail = audit_list_string; ++ iter->previous = NULL; ++} ++ ++/* Iterate through both audit_list_string and audit_list. */ ++static const char * ++audit_list_iter_next (struct audit_list_iter *iter) ++{ ++ if (iter->audit_list_tail != NULL) ++ { ++ /* First iterate over audit_list_string. */ ++ while (*iter->audit_list_tail != '\0') ++ { ++ /* Split audit list at colon. */ ++ size_t len = strcspn (iter->audit_list_tail, ":"); ++ if (len > 0 && len < sizeof (iter->fname)) ++ { ++ memcpy (iter->fname, iter->audit_list_tail, len); ++ iter->fname[len] = '\0'; ++ } ++ else ++ /* Do not return this name to the caller. */ ++ iter->fname[0] = '\0'; ++ ++ /* Skip over the substring and the following delimiter. */ ++ iter->audit_list_tail += len; ++ if (*iter->audit_list_tail == ':') ++ ++iter->audit_list_tail; ++ ++ /* If the name is valid, return it. */ ++ if (dso_name_valid_for_suid (iter->fname)) ++ return iter->fname; ++ /* Otherwise, wrap around and try the next name. */ ++ } ++ /* Fall through to the procesing of audit_list. */ ++ } ++ ++ if (iter->previous == NULL) ++ { ++ if (audit_list == NULL) ++ /* No pre-parsed audit list. */ ++ return NULL; ++ /* Start of audit list. The first list element is at ++ audit_list->next (cyclic list). */ ++ iter->previous = audit_list->next; ++ return iter->previous->name; ++ } ++ if (iter->previous == audit_list) ++ /* Cyclic list wrap-around. */ ++ return NULL; ++ iter->previous = iter->previous->next; ++ return iter->previous->name; ++} ++ + #ifndef HAVE_INLINED_SYSCALLS + /* Set nonzero during loading and initialization of executable and + libraries, cleared before the executable's entry point runs. This +@@ -716,6 +823,42 @@ static const char *preloadlist attribute_relro; + /* Nonzero if information about versions has to be printed. */ + static int version_info attribute_relro; + ++/* The LD_PRELOAD environment variable gives list of libraries ++ separated by white space or colons that are loaded before the ++ executable's dependencies and prepended to the global scope list. ++ (If the binary is running setuid all elements containing a '/' are ++ ignored since it is insecure.) Return the number of preloads ++ performed. */ ++unsigned int ++handle_ld_preload (const char *preloadlist, struct link_map *main_map) ++{ ++ unsigned int npreloads = 0; ++ const char *p = preloadlist; ++ char fname[SECURE_PATH_LIMIT]; ++ ++ while (*p != '\0') ++ { ++ /* Split preload list at space/colon. */ ++ size_t len = strcspn (p, " :"); ++ if (len > 0 && len < sizeof (fname)) ++ { ++ memcpy (fname, p, len); ++ fname[len] = '\0'; ++ } ++ else ++ fname[0] = '\0'; ++ ++ /* Skip over the substring and the following delimiter. */ ++ p += len; ++ if (*p != '\0') ++ ++p; ++ ++ if (dso_name_valid_for_suid (fname)) ++ npreloads += do_preload (fname, main_map, "LD_PRELOAD"); ++ } ++ return npreloads; ++} ++ + static void + dl_main (const ElfW(Phdr) *phdr, + ElfW(Word) phnum, +@@ -1238,11 +1381,13 @@ of this helper program; chances are you did not intend to run this program.\n\ + GL(dl_rtld_map).l_tls_modid = _dl_next_tls_modid (); + + /* If we have auditing DSOs to load, do it now. */ +- if (__glibc_unlikely (audit_list != NULL)) ++ bool need_security_init = true; ++ if (__glibc_unlikely (audit_list != NULL) ++ || __glibc_unlikely (audit_list_string != NULL)) + { +- /* Iterate over all entries in the list. The order is important. */ + struct audit_ifaces *last_audit = NULL; +- struct audit_list *al = audit_list->next; ++ struct audit_list_iter al_iter; ++ audit_list_iter_init (&al_iter); + + /* Since we start using the auditing DSOs right away we need to + initialize the data structures now. */ +@@ -1253,9 +1398,14 @@ of this helper program; chances are you did not intend to run this program.\n\ + use different values (especially the pointer guard) and will + fail later on. */ + security_init (); ++ need_security_init = false; + +- do ++ while (true) + { ++ const char *name = audit_list_iter_next (&al_iter); ++ if (name == NULL) ++ break; ++ + int tls_idx = GL(dl_tls_max_dtv_idx); + + /* Now it is time to determine the layout of the static TLS +@@ -1264,7 +1414,7 @@ of this helper program; chances are you did not intend to run this program.\n\ + no DF_STATIC_TLS bit is set. The reason is that we know + glibc will use the static model. */ + struct dlmopen_args dlmargs; +- dlmargs.fname = al->name; ++ dlmargs.fname = name; + dlmargs.map = NULL; + + const char *objname; +@@ -1277,7 +1427,7 @@ of this helper program; chances are you did not intend to run this program.\n\ + not_loaded: + _dl_error_printf ("\ + ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", +- al->name, err_str); ++ name, err_str); + if (malloced) + free ((char *) err_str); + } +@@ -1381,10 +1531,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", + goto not_loaded; + } + } +- +- al = al->next; + } +- while (al != audit_list->next); + + /* If we have any auditing modules, announce that we already + have two objects loaded. */ +@@ -1462,23 +1609,8 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", + + if (__glibc_unlikely (preloadlist != NULL)) + { +- /* The LD_PRELOAD environment variable gives list of libraries +- separated by white space or colons that are loaded before the +- executable's dependencies and prepended to the global scope +- list. If the binary is running setuid all elements +- containing a '/' are ignored since it is insecure. */ +- char *list = strdupa (preloadlist); +- char *p; +- + HP_TIMING_NOW (start); +- +- /* Prevent optimizing strsep. Speed is not important here. */ +- while ((p = (strsep) (&list, " :")) != NULL) +- if (p[0] != '\0' +- && (__builtin_expect (! __libc_enable_secure, 1) +- || strchr (p, '/') == NULL)) +- npreloads += do_preload (p, main_map, "LD_PRELOAD"); +- ++ npreloads += handle_ld_preload (preloadlist, main_map); + HP_TIMING_NOW (stop); + HP_TIMING_DIFF (diff, start, stop); + HP_TIMING_ACCUM_NT (load_time, diff); +@@ -1663,7 +1795,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", + if (tcbp == NULL) + tcbp = init_tls (); + +- if (__glibc_likely (audit_list == NULL)) ++ if (__glibc_likely (need_security_init)) + /* Initialize security features. But only if we have not done it + earlier. */ + security_init (); +@@ -2294,9 +2426,7 @@ process_dl_audit (char *str) + char *p; + + while ((p = (strsep) (&str, ":")) != NULL) +- if (p[0] != '\0' +- && (__builtin_expect (! __libc_enable_secure, 1) +- || strchr (p, '/') == NULL)) ++ if (dso_name_valid_for_suid (p)) + { + /* This is using the local malloc, not the system malloc. The + memory can never be freed. */ +@@ -2360,7 +2490,7 @@ process_envvars (enum mode *modep) + break; + } + if (memcmp (envline, "AUDIT", 5) == 0) +- process_dl_audit (&envline[6]); ++ audit_list_string = &envline[6]; + break; + + case 7: +@@ -2404,7 +2534,8 @@ process_envvars (enum mode *modep) + + case 10: + /* Mask for the important hardware capabilities. */ +- if (memcmp (envline, "HWCAP_MASK", 10) == 0) ++ if (!__libc_enable_secure ++ && memcmp (envline, "HWCAP_MASK", 10) == 0) + GLRO(dl_hwcap_mask) = __strtoul_internal (&envline[11], NULL, + 0, 0); + break; +@@ -2418,7 +2549,8 @@ process_envvars (enum mode *modep) + + case 12: + /* The library search path. */ +- if (memcmp (envline, "LIBRARY_PATH", 12) == 0) ++ if (!__libc_enable_secure ++ && memcmp (envline, "LIBRARY_PATH", 12) == 0) + { + library_path = &envline[13]; + break; +diff --git a/elf/tst-env-setuid.c b/elf/tst-env-setuid.c +index 6ec3fa5874..eec408eb5d 100644 +--- a/elf/tst-env-setuid.c ++++ b/elf/tst-env-setuid.c +@@ -213,6 +213,12 @@ test_child (void) + return 1; + } + ++ if (getenv ("LD_HWCAP_MASK") != NULL) ++ { ++ printf ("LD_HWCAP_MASK still set\n"); ++ return 1; ++ } ++ + return 0; + } + #endif +@@ -233,6 +239,12 @@ test_parent (void) + return 1; + } + ++ if (getenv ("LD_HWCAP_MASK") == NULL) ++ { ++ printf ("LD_HWCAP_MASK lost\n"); ++ return 1; ++ } ++ + return 0; + } + #endif +diff --git a/grp/grp-merge.c b/grp/grp-merge.c +index 77c494d159..035e7a604b 100644 +--- a/grp/grp-merge.c ++++ b/grp/grp-merge.c +@@ -85,6 +85,14 @@ __copy_grp (const struct group srcgrp, const size_t buflen, + } + members[i] = NULL; + ++ /* Align for pointers. We can't simply align C because we need to ++ align destbuf[c]. */ ++ if ((((uintptr_t)destbuf + c) & (__alignof__(char **) - 1)) != 0) ++ { ++ uintptr_t mis_align = ((uintptr_t)destbuf + c) & (__alignof__(char **) - 1); ++ c += __alignof__(char **) - mis_align; ++ } ++ + /* Copy the pointers from the members array into the buffer and assign them + to the gr_mem member of destgrp. */ + destgrp->gr_mem = (char **) &destbuf[c]; +@@ -129,7 +137,7 @@ __merge_grp (struct group *savedgrp, char *savedbuf, char *savedend, + + /* Get the count of group members from the last sizeof (size_t) bytes in the + mergegrp buffer. */ +- savedmemcount = (size_t) *(savedend - sizeof (size_t)); ++ savedmemcount = *(size_t *) (savedend - sizeof (size_t)); + + /* Get the count of new members to add. */ + for (memcount = 0; mergegrp->gr_mem[memcount]; memcount++) +@@ -168,6 +176,14 @@ __merge_grp (struct group *savedgrp, char *savedbuf, char *savedend, + /* Add the NULL-terminator. */ + members[savedmemcount + memcount] = NULL; + ++ /* Align for pointers. We can't simply align C because we need to ++ align savedbuf[c]. */ ++ if ((((uintptr_t)savedbuf + c) & (__alignof__(char **) - 1)) != 0) ++ { ++ uintptr_t mis_align = ((uintptr_t)savedbuf + c) & (__alignof__(char **) - 1); ++ c += __alignof__(char **) - mis_align; ++ } ++ + /* Copy the member array back into the buffer after the member list and free + the member array. */ + savedgrp->gr_mem = (char **) &savedbuf[c]; +diff --git a/iconvdata/Makefile b/iconvdata/Makefile +index 04157b25c5..e4845871f5 100644 +--- a/iconvdata/Makefile ++++ b/iconvdata/Makefile +@@ -63,6 +63,11 @@ modules := ISO8859-1 ISO8859-2 ISO8859-3 ISO8859-4 ISO8859-5 \ + MAC-CENTRALEUROPE KOI8-RU ISO8859-9E \ + CP770 CP771 CP772 CP773 CP774 + ++# If lazy binding is disabled, use BIND_NOW for the gconv modules. ++ifeq ($(bind-now),yes) ++LDFLAGS.so += -Wl,-z,now ++endif ++ + modules.so := $(addsuffix .so, $(modules)) + + ifeq (yes,$(build-shared)) +diff --git a/include/array_length.h b/include/array_length.h +new file mode 100644 +index 0000000000..cb4a8b2a56 +--- /dev/null ++++ b/include/array_length.h +@@ -0,0 +1,36 @@ ++/* The array_length and array_end macros. ++ Copyright (C) 2017 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 ++ . */ ++ ++#ifndef _ARRAY_LENGTH_H ++#define _ARRAY_LENGTH_H ++ ++/* array_length (VAR) is the number of elements in the array VAR. VAR ++ must evaluate to an array, not a pointer. */ ++#define array_length(var) \ ++ __extension__ ({ \ ++ _Static_assert (!__builtin_types_compatible_p \ ++ (__typeof (var), __typeof (&(var)[0])), \ ++ "argument must be an array"); \ ++ sizeof (var) / sizeof ((var)[0]); \ ++ }) ++ ++/* array_end (VAR) is a pointer one past the end of the array VAR. ++ VAR must evaluate to an array, not a pointer. */ ++#define array_end(var) (&(var)[array_length (var)]) ++ ++#endif /* _ARRAY_LENGTH_H */ +diff --git a/include/resolv.h b/include/resolv.h +index 95dcd3ca37..e8f477cd86 100644 +--- a/include/resolv.h ++++ b/include/resolv.h +@@ -37,8 +37,6 @@ extern void res_pquery (const res_state __statp, const unsigned char *__msg, + extern int res_ourserver_p (const res_state __statp, + const struct sockaddr_in6 *__inp); + extern void __res_iclose (res_state statp, bool free_addr); +-extern int __res_nopt(res_state statp, int n0, unsigned char *buf, int buflen, +- int anslen); + libc_hidden_proto (__res_ninit) + libc_hidden_proto (__res_maybe_init) + libc_hidden_proto (__res_nclose) +@@ -91,7 +89,6 @@ libresolv_hidden_proto (__res_nameinquery) + libresolv_hidden_proto (__res_queriesmatch) + libresolv_hidden_proto (__res_nsend) + libresolv_hidden_proto (__b64_ntop) +-libresolv_hidden_proto (__res_nopt) + libresolv_hidden_proto (__dn_count_labels) + libresolv_hidden_proto (__p_secstodate) + +diff --git a/inet/Makefile b/inet/Makefile +index 010792af8f..6a7d3e0664 100644 +--- a/inet/Makefile ++++ b/inet/Makefile +@@ -45,14 +45,18 @@ routines := htonl htons \ + in6_addr getnameinfo if_index ifaddrs inet6_option \ + getipv4sourcefilter setipv4sourcefilter \ + getsourcefilter setsourcefilter inet6_opt inet6_rth \ +- inet6_scopeid_pton ++ inet6_scopeid_pton deadline + + aux := check_pf check_native ifreq + + tests := htontest test_ifindex tst-ntoa tst-ether_aton tst-network \ + tst-gethnm test-ifaddrs bug-if1 test-inet6_opt tst-ether_line \ + tst-getni1 tst-getni2 tst-inet6_rth tst-checks tst-checks-posix \ +- tst-sockaddr tst-inet6_scopeid_pton test-hnto-types ++ tst-sockaddr tst-inet6_scopeid_pton test-hnto-types tst-deadline ++ ++# tst-deadline must be linked statically so that we can access ++# internal functions. ++tests-static += tst-deadline + + include ../Rules + +diff --git a/inet/deadline.c b/inet/deadline.c +new file mode 100644 +index 0000000000..c1fa415a39 +--- /dev/null ++++ b/inet/deadline.c +@@ -0,0 +1,122 @@ ++/* Computing deadlines for timeouts. ++ Copyright (C) 2017 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 ++ . */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++struct deadline_current_time internal_function ++__deadline_current_time (void) ++{ ++ struct deadline_current_time result; ++ if (__clock_gettime (CLOCK_MONOTONIC, &result.current) != 0) ++ { ++ struct timeval current_tv; ++ if (__gettimeofday (¤t_tv, NULL) == 0) ++ __libc_fatal ("Fatal error: gettimeofday system call failed\n"); ++ result.current.tv_sec = current_tv.tv_sec; ++ result.current.tv_nsec = current_tv.tv_usec * 1000; ++ } ++ assert (result.current.tv_sec >= 0); ++ return result; ++} ++ ++/* A special deadline value for which __deadline_is_infinite is ++ true. */ ++static inline struct deadline ++infinite_deadline (void) ++{ ++ return (struct deadline) { { -1, -1 } }; ++} ++ ++struct deadline internal_function ++__deadline_from_timeval (struct deadline_current_time current, ++ struct timeval tv) ++{ ++ assert (__is_timeval_valid_timeout (tv)); ++ ++ /* Compute second-based deadline. Perform the addition in ++ uintmax_t, which is unsigned, to simply overflow detection. */ ++ uintmax_t sec = current.current.tv_sec; ++ sec += tv.tv_sec; ++ if (sec < (uintmax_t) tv.tv_sec) ++ return infinite_deadline (); ++ ++ /* Compute nanosecond deadline. */ ++ int nsec = current.current.tv_nsec + tv.tv_usec * 1000; ++ if (nsec >= 1000 * 1000 * 1000) ++ { ++ /* Carry nanosecond overflow to seconds. */ ++ nsec -= 1000 * 1000 * 1000; ++ if (sec + 1 < sec) ++ return infinite_deadline (); ++ ++sec; ++ } ++ /* This uses a GCC extension, otherwise these casts for detecting ++ overflow would not be defined. */ ++ if ((time_t) sec < 0 || sec != (uintmax_t) (time_t) sec) ++ return infinite_deadline (); ++ ++ return (struct deadline) { { sec, nsec } }; ++} ++ ++int internal_function ++__deadline_to_ms (struct deadline_current_time current, ++ struct deadline deadline) ++{ ++ if (__deadline_is_infinite (deadline)) ++ return INT_MAX; ++ ++ if (current.current.tv_sec > deadline.absolute.tv_sec ++ || (current.current.tv_sec == deadline.absolute.tv_sec ++ && current.current.tv_nsec >= deadline.absolute.tv_nsec)) ++ return 0; ++ time_t sec = deadline.absolute.tv_sec - current.current.tv_sec; ++ if (sec >= INT_MAX) ++ /* This value will overflow below. */ ++ return INT_MAX; ++ int nsec = deadline.absolute.tv_nsec - current.current.tv_nsec; ++ if (nsec < 0) ++ { ++ /* Borrow from the seconds field. */ ++ assert (sec > 0); ++ --sec; ++ nsec += 1000 * 1000 * 1000; ++ } ++ ++ /* Prepare for rounding up to milliseconds. */ ++ nsec += 999999; ++ if (nsec > 1000 * 1000 * 1000) ++ { ++ assert (sec < INT_MAX); ++ ++sec; ++ nsec -= 1000 * 1000 * 1000; ++ } ++ ++ unsigned int msec = nsec / (1000 * 1000); ++ if (sec > INT_MAX / 1000) ++ return INT_MAX; ++ msec += sec * 1000; ++ if (msec > INT_MAX) ++ return INT_MAX; ++ return msec; ++} +diff --git a/inet/net-internal.h b/inet/net-internal.h +index 087597ed99..2b2632c7ba 100644 +--- a/inet/net-internal.h ++++ b/inet/net-internal.h +@@ -20,11 +20,100 @@ + #define _NET_INTERNAL_H 1 + + #include ++#include + #include ++#include + + int __inet6_scopeid_pton (const struct in6_addr *address, + const char *scope, uint32_t *result) + internal_function attribute_hidden; + libc_hidden_proto (__inet6_scopeid_pton) + ++ ++/* Deadline handling for enforcing timeouts. ++ ++ Code should call __deadline_current_time to obtain the current time ++ and cache it locally. The cache needs updating after every ++ long-running or potentially blocking operation. Deadlines relative ++ to the current time can be computed using __deadline_from_timeval. ++ The deadlines may have to be recomputed in response to certain ++ events (such as an incoming packet), but they are absolute (not ++ relative to the current time). A timeout suitable for use with the ++ poll function can be computed from such a deadline using ++ __deadline_to_ms. ++ ++ The fields in the structs defined belowed should only be used ++ within the implementation. */ ++ ++/* Cache of the current time. Used to compute deadlines from relative ++ timeouts and vice versa. */ ++struct deadline_current_time ++{ ++ struct timespec current; ++}; ++ ++/* Return the current time. Terminates the process if the current ++ time is not available. */ ++struct deadline_current_time __deadline_current_time (void) ++ internal_function attribute_hidden; ++ ++/* Computed absolute deadline. */ ++struct deadline ++{ ++ struct timespec absolute; ++}; ++ ++ ++/* For internal use only. */ ++static inline bool ++__deadline_is_infinite (struct deadline deadline) ++{ ++ return deadline.absolute.tv_nsec < 0; ++} ++ ++/* Return true if the current time is at the deadline or past it. */ ++static inline bool ++__deadline_elapsed (struct deadline_current_time current, ++ struct deadline deadline) ++{ ++ return !__deadline_is_infinite (deadline) ++ && (current.current.tv_sec > deadline.absolute.tv_sec ++ || (current.current.tv_sec == deadline.absolute.tv_sec ++ && current.current.tv_nsec >= deadline.absolute.tv_nsec)); ++} ++ ++/* Return the deadline which occurs first. */ ++static inline struct deadline ++__deadline_first (struct deadline left, struct deadline right) ++{ ++ if (__deadline_is_infinite (right) ++ || left.absolute.tv_sec < right.absolute.tv_sec ++ || (left.absolute.tv_sec == right.absolute.tv_sec ++ && left.absolute.tv_nsec < right.absolute.tv_nsec)) ++ return left; ++ else ++ return right; ++} ++ ++/* Add TV to the current time and return it. Returns a special ++ infinite absolute deadline on overflow. */ ++struct deadline __deadline_from_timeval (struct deadline_current_time, ++ struct timeval tv) ++ internal_function attribute_hidden; ++ ++/* Compute the number of milliseconds until the specified deadline, ++ from the current time in the argument. The result is mainly for ++ use with poll. If the deadline has already passed, return 0. If ++ the result would overflow an int, return INT_MAX. */ ++int __deadline_to_ms (struct deadline_current_time, struct deadline) ++ internal_function attribute_hidden; ++ ++/* Return true if TV.tv_sec is non-negative and TV.tv_usec is in the ++ interval [0, 999999]. */ ++static inline bool ++__is_timeval_valid_timeout (struct timeval tv) ++{ ++ return tv.tv_sec >= 0 && tv.tv_usec >= 0 && tv.tv_usec < 1000 * 1000; ++} ++ + #endif /* _NET_INTERNAL_H */ +diff --git a/inet/tst-deadline.c b/inet/tst-deadline.c +new file mode 100644 +index 0000000000..ed04345c35 +--- /dev/null ++++ b/inet/tst-deadline.c +@@ -0,0 +1,188 @@ ++/* Tests for computing deadlines for timeouts. ++ Copyright (C) 2017 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* Find the maximum value which can be represented in a time_t. */ ++static time_t ++time_t_max (void) ++{ ++ _Static_assert (0 > (time_t) -1, "time_t is signed"); ++ uintmax_t current = 1; ++ while (true) ++ { ++ uintmax_t next = current * 2; ++ /* This cannot happen because time_t is signed. */ ++ TEST_VERIFY_EXIT (next > current); ++ ++next; ++ if ((time_t) next < 0 || next != (uintmax_t) (time_t) next) ++ /* Value cannot be represented in time_t. Return the previous ++ value. */ ++ return current; ++ current = next; ++ } ++} ++ ++static int ++do_test (void) ++{ ++ { ++ struct deadline_current_time current_time = __deadline_current_time (); ++ TEST_VERIFY (current_time.current.tv_sec >= 0); ++ current_time = __deadline_current_time (); ++ /* Due to CLOCK_MONOTONIC, either seconds or nanoseconds are ++ greater than zero. This is also true for the gettimeofday ++ fallback. */ ++ TEST_VERIFY (current_time.current.tv_sec >= 0); ++ TEST_VERIFY (current_time.current.tv_sec > 0 ++ || current_time.current.tv_nsec > 0); ++ } ++ ++ /* Check basic computations of deadlines. */ ++ struct deadline_current_time current_time = { { 1, 123456789 } }; ++ struct deadline deadline = __deadline_from_timeval ++ (current_time, (struct timeval) { 0, 1 }); ++ TEST_VERIFY (deadline.absolute.tv_sec == 1); ++ TEST_VERIFY (deadline.absolute.tv_nsec == 123457789); ++ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 1); ++ ++ deadline = __deadline_from_timeval ++ (current_time, ((struct timeval) { 0, 2 })); ++ TEST_VERIFY (deadline.absolute.tv_sec == 1); ++ TEST_VERIFY (deadline.absolute.tv_nsec == 123458789); ++ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 1); ++ ++ deadline = __deadline_from_timeval ++ (current_time, ((struct timeval) { 1, 0 })); ++ TEST_VERIFY (deadline.absolute.tv_sec == 2); ++ TEST_VERIFY (deadline.absolute.tv_nsec == 123456789); ++ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 1000); ++ ++ /* Check if timeouts are correctly rounded up to the next ++ millisecond. */ ++ for (int i = 0; i < 999999; ++i) ++ { ++ ++current_time.current.tv_nsec; ++ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 1000); ++ } ++ ++ /* A full millisecond has elapsed, so the time to the deadline is ++ now less than 1000. */ ++ ++current_time.current.tv_nsec; ++ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 999); ++ ++ /* Check __deadline_to_ms carry-over. */ ++ current_time = (struct deadline_current_time) { { 9, 123456789 } }; ++ deadline = (struct deadline) { { 10, 122456789 } }; ++ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 999); ++ deadline = (struct deadline) { { 10, 122456790 } }; ++ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 1000); ++ deadline = (struct deadline) { { 10, 123456788 } }; ++ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 1000); ++ deadline = (struct deadline) { { 10, 123456789 } }; ++ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 1000); ++ ++ /* Check __deadline_to_ms overflow. */ ++ deadline = (struct deadline) { { INT_MAX - 1, 1 } }; ++ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == INT_MAX); ++ ++ /* Check __deadline_to_ms for elapsed deadlines. */ ++ current_time = (struct deadline_current_time) { { 9, 123456789 } }; ++ deadline.absolute = current_time.current; ++ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 0); ++ current_time = (struct deadline_current_time) { { 9, 123456790 } }; ++ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 0); ++ current_time = (struct deadline_current_time) { { 10, 0 } }; ++ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 0); ++ current_time = (struct deadline_current_time) { { 10, 123456788 } }; ++ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 0); ++ current_time = (struct deadline_current_time) { { 10, 123456789 } }; ++ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 0); ++ ++ /* Check carry-over in __deadline_from_timeval. */ ++ current_time = (struct deadline_current_time) { { 9, 998000001 } }; ++ for (int i = 0; i < 2000; ++i) ++ { ++ deadline = __deadline_from_timeval ++ (current_time, (struct timeval) { 1, i }); ++ TEST_VERIFY (deadline.absolute.tv_sec == 10); ++ TEST_VERIFY (deadline.absolute.tv_nsec == 998000001 + i * 1000); ++ } ++ for (int i = 2000; i < 3000; ++i) ++ { ++ deadline = __deadline_from_timeval ++ (current_time, (struct timeval) { 2, i }); ++ TEST_VERIFY (deadline.absolute.tv_sec == 12); ++ TEST_VERIFY (deadline.absolute.tv_nsec == 1 + (i - 2000) * 1000); ++ } ++ ++ /* Check infinite deadlines. */ ++ deadline = __deadline_from_timeval ++ ((struct deadline_current_time) { { 0, 1000 * 1000 * 1000 - 1000 } }, ++ (struct timeval) { time_t_max (), 1 }); ++ TEST_VERIFY (__deadline_is_infinite (deadline)); ++ deadline = __deadline_from_timeval ++ ((struct deadline_current_time) { { 0, 1000 * 1000 * 1000 - 1001 } }, ++ (struct timeval) { time_t_max (), 1 }); ++ TEST_VERIFY (!__deadline_is_infinite (deadline)); ++ deadline = __deadline_from_timeval ++ ((struct deadline_current_time) ++ { { time_t_max (), 1000 * 1000 * 1000 - 1000 } }, ++ (struct timeval) { 0, 1 }); ++ TEST_VERIFY (__deadline_is_infinite (deadline)); ++ deadline = __deadline_from_timeval ++ ((struct deadline_current_time) ++ { { time_t_max () / 2 + 1, 0 } }, ++ (struct timeval) { time_t_max () / 2 + 1, 0 }); ++ TEST_VERIFY (__deadline_is_infinite (deadline)); ++ ++ /* Check __deadline_first behavior. */ ++ deadline = __deadline_first ++ ((struct deadline) { { 1, 2 } }, ++ (struct deadline) { { 1, 3 } }); ++ TEST_VERIFY (deadline.absolute.tv_sec == 1); ++ TEST_VERIFY (deadline.absolute.tv_nsec == 2); ++ deadline = __deadline_first ++ ((struct deadline) { { 1, 3 } }, ++ (struct deadline) { { 1, 2 } }); ++ TEST_VERIFY (deadline.absolute.tv_sec == 1); ++ TEST_VERIFY (deadline.absolute.tv_nsec == 2); ++ deadline = __deadline_first ++ ((struct deadline) { { 1, 2 } }, ++ (struct deadline) { { 2, 1 } }); ++ TEST_VERIFY (deadline.absolute.tv_sec == 1); ++ TEST_VERIFY (deadline.absolute.tv_nsec == 2); ++ deadline = __deadline_first ++ ((struct deadline) { { 1, 2 } }, ++ (struct deadline) { { 2, 4 } }); ++ TEST_VERIFY (deadline.absolute.tv_sec == 1); ++ TEST_VERIFY (deadline.absolute.tv_nsec == 2); ++ deadline = __deadline_first ++ ((struct deadline) { { 2, 4 } }, ++ (struct deadline) { { 1, 2 } }); ++ TEST_VERIFY (deadline.absolute.tv_sec == 1); ++ TEST_VERIFY (deadline.absolute.tv_nsec == 2); ++ ++ return 0; ++} ++ ++#include +diff --git a/io/fts.h b/io/fts.h +index b9cff534e9..ab15567001 100644 +--- a/io/fts.h ++++ b/io/fts.h +@@ -193,7 +193,7 @@ FTS *__REDIRECT (fts_open, (char * const *, int, + int (*)(const FTSENT **, const FTSENT **)), + fts64_open); + FTSENT *__REDIRECT (fts_read, (FTS *), fts64_read); +-int __REDIRECT (fts_set, (FTS *, FTSENT *, int), fts64_set) __THROW; ++int __REDIRECT_NTH (fts_set, (FTS *, FTSENT *, int), fts64_set); + # else + # define fts_children fts64_children + # define fts_close fts64_close +diff --git a/localedata/ChangeLog b/localedata/ChangeLog +index 0cdb097ab6..127c1cfb35 100644 +--- a/localedata/ChangeLog ++++ b/localedata/ChangeLog +@@ -1,3 +1,11 @@ ++2017-06-11 Santhosh Thottingal ++ ++ [BZ #19922] ++ * locales/iso14651_t1_common: Add collation rules for U+07DA to U+07DF. ++ ++ [BZ #19919] ++ * locales/iso14651_t1_common: Correct collation of U+0D36 and U+0D37. ++ + 2017-01-01 Joseph Myers + + * All files with FSF copyright notices: Update copyright dates +diff --git a/localedata/locales/iso14651_t1_common b/localedata/locales/iso14651_t1_common +index eef75ba65e..0e64f26a12 100644 +--- a/localedata/locales/iso14651_t1_common ++++ b/localedata/locales/iso14651_t1_common +@@ -1042,9 +1042,9 @@ collating-element from "" + collating-element from "" + collating-element from "" + collating-element from "" +-collating-element from "" + collating-element from "" + collating-element from "" ++collating-element from "" + collating-element from "" + collating-element from "" + collating-element from "" +@@ -1103,8 +1103,8 @@ collating-symbol + collating-symbol + collating-symbol + collating-symbol +-collating-symbol + collating-symbol ++collating-symbol + collating-symbol + collating-symbol + collating-symbol +@@ -1126,6 +1126,12 @@ collating-symbol + collating-symbol + collating-symbol + collating-symbol ++collating-symbol ++collating-symbol ++collating-symbol ++collating-symbol ++collating-symbol ++collating-symbol + # + # + # +@@ -4552,6 +4558,12 @@ collating-symbol + + + ++ ++ ++ ++ ++ ++ + # + # + # +@@ -7252,6 +7264,7 @@ order_start ;forward;forward;forward;forward,position + ;;;IGNORE + ;;;IGNORE + "";;;IGNORE ++ "";;;IGNORE + "";;;IGNORE + "";;;IGNORE + "";;;IGNORE +@@ -7280,6 +7293,7 @@ order_start ;forward;forward;forward;forward,position + "";;;IGNORE + "";;;IGNORE + "";;;IGNORE # ണ്‍ = ണ + ് + zwj ++ "";;;IGNORE + "";;;IGNORE # ണ = ണ + ് + അ + "";;;IGNORE + "";;;IGNORE +@@ -7290,6 +7304,7 @@ order_start ;forward;forward;forward;forward,position + "";;;IGNORE + "";;;IGNORE + "";;;IGNORE # ന്‍= ന + ് + zwj ++ "";;;IGNORE + "";;;IGNORE #ന = ന + ് + അ + "";;;IGNORE + "";;;IGNORE +@@ -7305,20 +7320,23 @@ order_start ;forward;forward;forward;forward,position + "";;;IGNORE + "";;;IGNORE + "";;;IGNORE # ര = ര + ് + zwj ++ "";;;IGNORE + "";;;IGNORE # ര = ര + ് + അ + ;;;IGNORE # ല്‍ = ല + ് + zwj ++ "";;;IGNORE + "";;;IGNORE # ല = ല + ് + അ + "";;;IGNORE + "";;;IGNORE + "";;;IGNORE +- "";;;IGNORE ++ "";;;IGNORE + "";;;IGNORE +- "";;;IGNORE ++ "";;;IGNORE + "";;;IGNORE + "";;;IGNORE + "";;;IGNORE + "";;;IGNORE + "";;;IGNORE # ള്‍ = ള + ് + zwj ++ "";;;IGNORE + "";;;IGNORE # ള = ള + ് + അ + "";;;IGNORE + "";;;IGNORE +diff --git a/malloc/arena.c b/malloc/arena.c +index b91d7d6b16..d49e4a21c8 100644 +--- a/malloc/arena.c ++++ b/malloc/arena.c +@@ -212,9 +212,9 @@ __malloc_fork_unlock_child (void) + #if HAVE_TUNABLES + static inline int do_set_mallopt_check (int32_t value); + void +-DL_TUNABLE_CALLBACK (set_mallopt_check) (void *valp) ++DL_TUNABLE_CALLBACK (set_mallopt_check) (tunable_val_t *valp) + { +- int32_t value = *(int32_t *) valp; ++ int32_t value = (int32_t) valp->numval; + do_set_mallopt_check (value); + if (check_action != 0) + __malloc_check_init (); +@@ -223,9 +223,9 @@ DL_TUNABLE_CALLBACK (set_mallopt_check) (void *valp) + # define DL_TUNABLE_CALLBACK_FNDECL(__name, __type) \ + static inline int do_ ## __name (__type value); \ + void \ +-DL_TUNABLE_CALLBACK (__name) (void *valp) \ ++DL_TUNABLE_CALLBACK (__name) (tunable_val_t *valp) \ + { \ +- __type value = *(__type *) valp; \ ++ __type value = (__type) (valp)->numval; \ + do_ ## __name (value); \ + } + +diff --git a/malloc/malloc.c b/malloc/malloc.c +index 4885793905..4e076638b0 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -4902,7 +4902,7 @@ __libc_mallopt (int param_number, int value) + + case M_ARENA_MAX: + if (value > 0) +- do_set_arena_test (value); ++ do_set_arena_max (value); + break; + } + __libc_lock_unlock (av->mutex); +diff --git a/misc/regexp.c b/misc/regexp.c +index 19d76c0c37..eaea7c3b89 100644 +--- a/misc/regexp.c ++++ b/misc/regexp.c +@@ -29,14 +29,15 @@ + + #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_23) + +-/* Define the variables used for the interface. */ +-char *loc1; +-char *loc2; ++/* Define the variables used for the interface. Avoid .symver on common ++ symbol, which just creates a new common symbol, not an alias. */ ++char *loc1 __attribute__ ((nocommon)); ++char *loc2 __attribute__ ((nocommon)); + compat_symbol (libc, loc1, loc1, GLIBC_2_0); + compat_symbol (libc, loc2, loc2, GLIBC_2_0); + + /* Although we do not support the use we define this variable as well. */ +-char *locs; ++char *locs __attribute__ ((nocommon)); + compat_symbol (libc, locs, locs, GLIBC_2_0); + + +diff --git a/nptl/Makefile b/nptl/Makefile +index 6d48c0cfc8..8def69ae22 100644 +--- a/nptl/Makefile ++++ b/nptl/Makefile +@@ -224,6 +224,7 @@ tests = tst-typesizes \ + tst-attr1 tst-attr2 tst-attr3 tst-default-attr \ + tst-mutex1 tst-mutex2 tst-mutex3 tst-mutex4 tst-mutex5 tst-mutex6 \ + tst-mutex7 tst-mutex8 tst-mutex9 tst-mutex5a tst-mutex7a \ ++ tst-mutex7robust \ + tst-mutexpi1 tst-mutexpi2 tst-mutexpi3 tst-mutexpi4 tst-mutexpi5 \ + tst-mutexpi5a tst-mutexpi6 tst-mutexpi7 tst-mutexpi7a tst-mutexpi8 \ + tst-mutexpi9 \ +@@ -241,7 +242,7 @@ tests = tst-typesizes \ + tst-rwlock4 tst-rwlock5 tst-rwlock6 tst-rwlock7 tst-rwlock8 \ + tst-rwlock9 tst-rwlock10 tst-rwlock11 tst-rwlock12 tst-rwlock13 \ + tst-rwlock14 tst-rwlock15 tst-rwlock16 tst-rwlock17 tst-rwlock18 \ +- tst-rwlock19 \ ++ tst-rwlock19 tst-rwlock20 \ + tst-once1 tst-once2 tst-once3 tst-once4 tst-once5 \ + tst-key1 tst-key2 tst-key3 tst-key4 \ + tst-sem1 tst-sem2 tst-sem3 tst-sem4 tst-sem5 tst-sem6 tst-sem7 \ +@@ -355,7 +356,7 @@ tests += tst-cancelx2 tst-cancelx3 tst-cancelx4 tst-cancelx5 \ + tst-oncex3 tst-oncex4 + ifeq ($(build-shared),yes) + tests += tst-atfork2 tst-tls3 tst-tls3-malloc tst-tls4 tst-tls5 tst-_res1 \ +- tst-fini1 tst-stackguard1 ++ tst-fini1 tst-stackguard1 tst-compat-forwarder + tests-nolibpthread += tst-fini1 + ifeq ($(have-z-execstack),yes) + tests += tst-execstack +@@ -366,7 +367,7 @@ modules-names = tst-atfork2mod tst-tls3mod tst-tls4moda tst-tls4modb \ + tst-tls5mod tst-tls5moda tst-tls5modb tst-tls5modc \ + tst-tls5modd tst-tls5mode tst-tls5modf tst-stack4mod \ + tst-_res1mod1 tst-_res1mod2 tst-execstack-mod tst-fini1mod \ +- tst-join7mod ++ tst-join7mod tst-compat-forwarder-mod + extra-test-objs += $(addsuffix .os,$(strip $(modules-names))) \ + tst-cleanup4aux.o tst-cleanupx4aux.o + test-extras += $(modules-names) tst-cleanup4aux tst-cleanupx4aux +@@ -704,6 +705,8 @@ $(objpfx)tst-oddstacklimit.out: $(objpfx)tst-oddstacklimit $(objpfx)tst-basic1 + $(evaluate-test) + endif + ++$(objpfx)tst-compat-forwarder: $(objpfx)tst-compat-forwarder-mod.so ++ + # The tests here better do not run in parallel + ifneq ($(filter %tests,$(MAKECMDGOALS)),) + .NOTPARALLEL: +diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c +index 8a228ab254..368fe3c36b 100644 +--- a/nptl/allocatestack.c ++++ b/nptl/allocatestack.c +@@ -683,8 +683,14 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp, + prot) != 0) + goto mprot_error; + #elif _STACK_GROWS_UP +- if (mprotect ((char *) pd - pd->guardsize, +- pd->guardsize - guardsize, prot) != 0) ++ char *new_guard = (char *)(((uintptr_t) pd - guardsize) ++ & ~pagesize_m1); ++ char *old_guard = (char *)(((uintptr_t) pd - pd->guardsize) ++ & ~pagesize_m1); ++ /* The guard size difference might be > 0, but once rounded ++ to the nearest page the size difference might be zero. */ ++ if (new_guard > old_guard ++ && mprotect (old_guard, new_guard - old_guard, prot) != 0) + goto mprot_error; + #endif + +diff --git a/nptl/pt-longjmp.c b/nptl/pt-longjmp.c +index 2ef757e687..8f3c6b3a09 100644 +--- a/nptl/pt-longjmp.c ++++ b/nptl/pt-longjmp.c +@@ -25,21 +25,14 @@ + symbol in libpthread, but the historical ABI requires it. For static + linking, there is no need to provide anything here--the libc version + will be linked in. For shared library ABI compatibility, there must be +- longjmp and siglongjmp symbols in libpthread.so; so we define them using +- IFUNC to redirect to the libc function. */ ++ longjmp and siglongjmp symbols in libpthread.so. + +-#if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_22) +- +-# if HAVE_IFUNC +- +-# undef INIT_ARCH +-# define INIT_ARCH() +-# define DEFINE_LONGJMP(name) libc_ifunc (name, &__libc_longjmp) +- +-extern __typeof(longjmp) longjmp_ifunc; +-extern __typeof(siglongjmp) siglongjmp_ifunc; ++ With an IFUNC resolver, it would be possible to avoid the indirection, ++ but the IFUNC resolver might run before the __libc_longjmp symbol has ++ been relocated, in which case the IFUNC resolver would not be able to ++ provide the correct address. */ + +-# else /* !HAVE_IFUNC */ ++#if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_22) + + static void __attribute__ ((noreturn, used)) + longjmp_compat (jmp_buf env, int val) +@@ -47,14 +40,10 @@ longjmp_compat (jmp_buf env, int val) + __libc_longjmp (env, val); + } + +-# define DEFINE_LONGJMP(name) strong_alias (longjmp_compat, name) +- +-# endif /* HAVE_IFUNC */ +- +-DEFINE_LONGJMP (longjmp_ifunc) +-compat_symbol (libpthread, longjmp_ifunc, longjmp, GLIBC_2_0); ++strong_alias (longjmp_compat, longjmp_alias) ++compat_symbol (libpthread, longjmp_alias, longjmp, GLIBC_2_0); + +-strong_alias (longjmp_ifunc, siglongjmp_ifunc) +-compat_symbol (libpthread, siglongjmp_ifunc, siglongjmp, GLIBC_2_0); ++strong_alias (longjmp_alias, siglongjmp_alias) ++compat_symbol (libpthread, siglongjmp_alias, siglongjmp, GLIBC_2_0); + + #endif +diff --git a/nptl/pt-system.c b/nptl/pt-system.c +index f8ca6ba0d9..b30ddf2b39 100644 +--- a/nptl/pt-system.c ++++ b/nptl/pt-system.c +@@ -25,29 +25,21 @@ + libpthread, but the historical ABI requires it. For static linking, + there is no need to provide anything here--the libc version will be + linked in. For shared library ABI compatibility, there must be a +- 'system' symbol in libpthread.so; so we define it using IFUNC to +- redirect to the libc function. */ ++ 'system' symbol in libpthread.so. + +-#if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_22) +- +-# if HAVE_IFUNC +- +-extern __typeof(system) system_ifunc; +-# undef INIT_ARCH +-# define INIT_ARCH() +-libc_ifunc (system_ifunc, &__libc_system) ++ With an IFUNC resolver, it would be possible to avoid the indirection, ++ but the IFUNC resolver might run before the __libc_system symbol has ++ been relocated, in which case the IFUNC resolver would not be able to ++ provide the correct address. */ + +-# else /* !HAVE_IFUNC */ ++#if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_22) + + static int __attribute__ ((used)) + system_compat (const char *line) + { + return __libc_system (line); + } +-strong_alias (system_compat, system_ifunc) +- +-# endif /* HAVE_IFUNC */ +- +-compat_symbol (libpthread, system_ifunc, system, GLIBC_2_0); ++strong_alias (system_compat, system_alias) ++compat_symbol (libpthread, system_alias, system, GLIBC_2_0); + + #endif +diff --git a/nptl/pthread_mutex_lock.c b/nptl/pthread_mutex_lock.c +index dc9ca4c476..4425927c30 100644 +--- a/nptl/pthread_mutex_lock.c ++++ b/nptl/pthread_mutex_lock.c +@@ -197,11 +197,14 @@ __pthread_mutex_lock_full (pthread_mutex_t *mutex) + { + /* Try to acquire the lock through a CAS from 0 (not acquired) to + our TID | assume_other_futex_waiters. */ +- if (__glibc_likely ((oldval == 0) +- && (atomic_compare_and_exchange_bool_acq +- (&mutex->__data.__lock, +- id | assume_other_futex_waiters, 0) == 0))) +- break; ++ if (__glibc_likely (oldval == 0)) ++ { ++ oldval ++ = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock, ++ id | assume_other_futex_waiters, 0); ++ if (__glibc_likely (oldval == 0)) ++ break; ++ } + + if ((oldval & FUTEX_OWNER_DIED) != 0) + { +diff --git a/nptl/pthread_mutex_timedlock.c b/nptl/pthread_mutex_timedlock.c +index a4beb7b0dc..dd88cc4ec9 100644 +--- a/nptl/pthread_mutex_timedlock.c ++++ b/nptl/pthread_mutex_timedlock.c +@@ -154,11 +154,14 @@ pthread_mutex_timedlock (pthread_mutex_t *mutex, + { + /* Try to acquire the lock through a CAS from 0 (not acquired) to + our TID | assume_other_futex_waiters. */ +- if (__glibc_likely ((oldval == 0) +- && (atomic_compare_and_exchange_bool_acq +- (&mutex->__data.__lock, +- id | assume_other_futex_waiters, 0) == 0))) +- break; ++ if (__glibc_likely (oldval == 0)) ++ { ++ oldval ++ = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock, ++ id | assume_other_futex_waiters, 0); ++ if (__glibc_likely (oldval == 0)) ++ break; ++ } + + if ((oldval & FUTEX_OWNER_DIED) != 0) + { +diff --git a/nptl/pthread_rwlock_common.c b/nptl/pthread_rwlock_common.c +index 256508ca2a..846687e1cf 100644 +--- a/nptl/pthread_rwlock_common.c ++++ b/nptl/pthread_rwlock_common.c +@@ -55,7 +55,6 @@ + lock acquisition attempts, so that new incoming readers do not prolong a + phase in which readers have acquired the lock. + +- + The main components of the rwlock are a writer-only lock that allows only + one of the concurrent writers to be the primary writer, and a + single-writer-multiple-readers lock that decides between read phases, in +@@ -70,15 +69,16 @@ + --------------------------- + #1 0 0 0 0 Lock is idle (and in a read phase). + #2 0 0 >0 0 Readers have acquired the lock. +- #3 0 1 0 0 Lock is not acquired; a writer is waiting for a write +- phase to start or will try to start one. ++ #3 0 1 0 0 Lock is not acquired; a writer will try to start a ++ write phase. + #4 0 1 >0 0 Readers have acquired the lock; a writer is waiting + and explicit hand-over to the writer is required. + #4a 0 1 >0 1 Same as #4 except that there are further readers + waiting because the writer is to be preferred. + #5 1 0 0 0 Lock is idle (and in a write phase). +- #6 1 0 >0 0 Write phase; readers are waiting for a read phase to +- start or will try to start one. ++ #6 1 0 >0 0 Write phase; readers will try to start a read phase ++ (requires explicit hand-over to all readers that ++ do not start the read phase). + #7 1 1 0 0 Lock is acquired by a writer. + #8 1 1 >0 0 Lock acquired by a writer and readers are waiting; + explicit hand-over to the readers is required. +@@ -375,9 +375,9 @@ __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock, + complexity. */ + if (__glibc_likely ((r & PTHREAD_RWLOCK_WRPHASE) == 0)) + return 0; +- +- /* If there is no primary writer but we are in a write phase, we can try +- to install a read phase ourself. */ ++ /* Otherwise, if we were in a write phase (states #6 or #8), we must wait ++ for explicit hand-over of the read phase; the only exception is if we ++ can start a read phase if there is no primary writer currently. */ + while (((r & PTHREAD_RWLOCK_WRPHASE) != 0) + && ((r & PTHREAD_RWLOCK_WRLOCKED) == 0)) + { +@@ -390,15 +390,18 @@ __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock, + { + /* 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 us because other readers cannot ++ distinguish between us and the writer; this includes ++ explicit hand-over and potentially having to wake other readers ++ (but we can pretend to do the setting and unsetting of WRLOCKED ++ atomically, and thus can skip this step). */ ++ 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; + } + else +@@ -407,102 +410,98 @@ __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock, + } + } + +- if ((r & PTHREAD_RWLOCK_WRPHASE) != 0) ++ /* We were in a write phase but did not install the read phase. We cannot ++ distinguish between a writer and another reader starting the read phase, ++ so we must wait for explicit hand-over via __wrphase_futex. ++ However, __wrphase_futex might not have been set to 1 yet (either ++ because explicit hand-over to the writer is still ongoing, or because ++ the writer has started the write phase but has not yet updated ++ __wrphase_futex). The least recent value of __wrphase_futex we can ++ read from here is the modification of the last read phase (because ++ we synchronize with the last reader in this read phase through ++ __readers; see the use of acquire MO on the fetch_add above). ++ Therefore, if we observe a value of 0 for __wrphase_futex, we need ++ to subsequently check that __readers now indicates a read phase; we ++ need to use acquire MO for this so that if we observe a read phase, ++ we will also see the modification of __wrphase_futex by the previous ++ writer. We then need to load __wrphase_futex again and continue to ++ wait if it is not 0, so that we do not skip explicit hand-over. ++ Relaxed MO is sufficient for the load from __wrphase_futex because ++ we just use it as an indicator for when we can proceed; we use ++ __readers and the acquire MO accesses to it to eventually read from ++ the proper stores to __wrphase_futex. */ ++ unsigned int wpf; ++ bool ready = false; ++ for (;;) + { +- /* We are in a write phase, and there must be a primary writer because +- of the previous loop. Block until the primary writer gives up the +- write phase. This case requires explicit hand-over using +- __wrphase_futex. +- However, __wrphase_futex might not have been set to 1 yet (either +- because explicit hand-over to the writer is still ongoing, or because +- the writer has started the write phase but does not yet have updated +- __wrphase_futex). The least recent value of __wrphase_futex we can +- read from here is the modification of the last read phase (because +- we synchronize with the last reader in this read phase through +- __readers; see the use of acquire MO on the fetch_add above). +- Therefore, if we observe a value of 0 for __wrphase_futex, we need +- to subsequently check that __readers now indicates a read phase; we +- need to use acquire MO for this so that if we observe a read phase, +- we will also see the modification of __wrphase_futex by the previous +- writer. We then need to load __wrphase_futex again and continue to +- wait if it is not 0, so that we do not skip explicit hand-over. +- Relaxed MO is sufficient for the load from __wrphase_futex because +- we just use it as an indicator for when we can proceed; we use +- __readers and the acquire MO accesses to it to eventually read from +- the proper stores to __wrphase_futex. */ +- unsigned int wpf; +- bool ready = false; +- for (;;) ++ while (((wpf = atomic_load_relaxed (&rwlock->__data.__wrphase_futex)) ++ | PTHREAD_RWLOCK_FUTEX_USED) == (1 | PTHREAD_RWLOCK_FUTEX_USED)) + { +- while (((wpf = atomic_load_relaxed (&rwlock->__data.__wrphase_futex)) +- | PTHREAD_RWLOCK_FUTEX_USED) == (1 | PTHREAD_RWLOCK_FUTEX_USED)) ++ int private = __pthread_rwlock_get_private (rwlock); ++ if (((wpf & PTHREAD_RWLOCK_FUTEX_USED) == 0) ++ && !atomic_compare_exchange_weak_relaxed ++ (&rwlock->__data.__wrphase_futex, ++ &wpf, wpf | PTHREAD_RWLOCK_FUTEX_USED)) ++ continue; ++ int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex, ++ 1 | PTHREAD_RWLOCK_FUTEX_USED, abstime, private); ++ if (err == ETIMEDOUT) + { +- int private = __pthread_rwlock_get_private (rwlock); +- if (((wpf & PTHREAD_RWLOCK_FUTEX_USED) == 0) +- && !atomic_compare_exchange_weak_relaxed +- (&rwlock->__data.__wrphase_futex, +- &wpf, wpf | PTHREAD_RWLOCK_FUTEX_USED)) +- continue; +- int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex, +- 1 | PTHREAD_RWLOCK_FUTEX_USED, abstime, private); +- if (err == ETIMEDOUT) ++ /* If we timed out, we need to unregister. If no read phase ++ has been installed while we waited, we can just decrement ++ the number of readers. Otherwise, we just acquire the ++ lock, which is allowed because we give no precise timing ++ guarantees, and because the timeout is only required to ++ be in effect if we would have had to wait for other ++ threads (e.g., if futex_wait would time-out immediately ++ because the given absolute time is in the past). */ ++ r = atomic_load_relaxed (&rwlock->__data.__readers); ++ while ((r & PTHREAD_RWLOCK_WRPHASE) != 0) + { +- /* If we timed out, we need to unregister. If no read phase +- has been installed while we waited, we can just decrement +- the number of readers. Otherwise, we just acquire the +- lock, which is allowed because we give no precise timing +- guarantees, and because the timeout is only required to +- be in effect if we would have had to wait for other +- threads (e.g., if futex_wait would time-out immediately +- because the given absolute time is in the past). */ +- r = atomic_load_relaxed (&rwlock->__data.__readers); +- while ((r & PTHREAD_RWLOCK_WRPHASE) != 0) +- { +- /* We don't need to make anything else visible to +- others besides unregistering, so relaxed MO is +- sufficient. */ +- if (atomic_compare_exchange_weak_relaxed +- (&rwlock->__data.__readers, &r, +- r - (1 << PTHREAD_RWLOCK_READER_SHIFT))) +- return ETIMEDOUT; +- /* TODO Back-off. */ +- } +- /* Use the acquire MO fence to mirror the steps taken in the +- non-timeout case. Note that the read can happen both +- in the atomic_load above as well as in the failure case +- of the CAS operation. */ +- atomic_thread_fence_acquire (); +- /* We still need to wait for explicit hand-over, but we must +- not use futex_wait anymore because we would just time out +- in this case and thus make the spin-waiting we need +- unnecessarily expensive. */ +- while ((atomic_load_relaxed (&rwlock->__data.__wrphase_futex) +- | PTHREAD_RWLOCK_FUTEX_USED) +- == (1 | PTHREAD_RWLOCK_FUTEX_USED)) +- { +- /* TODO Back-off? */ +- } +- ready = true; +- break; ++ /* We don't need to make anything else visible to ++ others besides unregistering, so relaxed MO is ++ sufficient. */ ++ if (atomic_compare_exchange_weak_relaxed ++ (&rwlock->__data.__readers, &r, ++ r - (1 << PTHREAD_RWLOCK_READER_SHIFT))) ++ return ETIMEDOUT; ++ /* TODO Back-off. */ + } +- /* If we got interrupted (EINTR) or the futex word does not have the +- expected value (EAGAIN), retry. */ ++ /* Use the acquire MO fence to mirror the steps taken in the ++ non-timeout case. Note that the read can happen both ++ in the atomic_load above as well as in the failure case ++ of the CAS operation. */ ++ atomic_thread_fence_acquire (); ++ /* We still need to wait for explicit hand-over, but we must ++ not use futex_wait anymore because we would just time out ++ in this case and thus make the spin-waiting we need ++ unnecessarily expensive. */ ++ while ((atomic_load_relaxed (&rwlock->__data.__wrphase_futex) ++ | PTHREAD_RWLOCK_FUTEX_USED) ++ == (1 | PTHREAD_RWLOCK_FUTEX_USED)) ++ { ++ /* TODO Back-off? */ ++ } ++ ready = true; ++ break; + } +- if (ready) +- /* See below. */ +- break; +- /* We need acquire MO here so that we synchronize with the lock +- release of the writer, and so that we observe a recent value of +- __wrphase_futex (see below). */ +- if ((atomic_load_acquire (&rwlock->__data.__readers) +- & PTHREAD_RWLOCK_WRPHASE) == 0) +- /* We are in a read phase now, so the least recent modification of +- __wrphase_futex we can read from is the store by the writer +- with value 1. Thus, only now we can assume that if we observe +- a value of 0, explicit hand-over is finished. Retry the loop +- above one more time. */ +- ready = true; ++ /* If we got interrupted (EINTR) or the futex word does not have the ++ expected value (EAGAIN), retry. */ + } ++ if (ready) ++ /* See below. */ ++ break; ++ /* We need acquire MO here so that we synchronize with the lock ++ release of the writer, and so that we observe a recent value of ++ __wrphase_futex (see below). */ ++ if ((atomic_load_acquire (&rwlock->__data.__readers) ++ & PTHREAD_RWLOCK_WRPHASE) == 0) ++ /* We are in a read phase now, so the least recent modification of ++ __wrphase_futex we can read from is the store by the writer ++ with value 1. Thus, only now we can assume that if we observe ++ a value of 0, explicit hand-over is finished. Retry the loop ++ above one more time. */ ++ ready = true; + } + + return 0; +@@ -741,10 +740,23 @@ __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock, + r = atomic_load_relaxed (&rwlock->__data.__readers); + } + /* Our snapshot of __readers is up-to-date at this point because we +- either set WRLOCKED using a CAS or were handed over WRLOCKED from ++ either set WRLOCKED using a CAS (and update r accordingly below, ++ which was used as expected value for the CAS) or got WRLOCKED from + another writer whose snapshot of __readers we inherit. */ ++ r |= PTHREAD_RWLOCK_WRLOCKED; + } + ++ /* We are the primary writer; enable blocking on __writers_futex. Relaxed ++ MO is sufficient for futex words; acquire MO on the previous ++ modifications of __readers ensures that this store happens after the ++ store of value 0 by the previous primary writer. */ ++ atomic_store_relaxed (&rwlock->__data.__writers_futex, ++ 1 | (may_share_futex_used_flag ? PTHREAD_RWLOCK_FUTEX_USED : 0)); ++ ++ /* If we are in a write phase, we have acquired the lock. */ ++ if ((r & PTHREAD_RWLOCK_WRPHASE) != 0) ++ goto done; ++ + /* If we are in a read phase and there are no readers, try to start a write + phase. */ + while (((r & PTHREAD_RWLOCK_WRPHASE) == 0) +@@ -758,166 +770,156 @@ __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock, + &r, r | PTHREAD_RWLOCK_WRPHASE)) + { + /* We have started a write phase, so need to enable readers to wait. +- See the similar case in__pthread_rwlock_rdlock_full. */ ++ See the similar case in __pthread_rwlock_rdlock_full. Unlike in ++ that similar case, we are the (only) primary writer and so do ++ not need to wake another writer. */ + atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 1); +- /* Make sure we fall through to the end of the function. */ +- r |= PTHREAD_RWLOCK_WRPHASE; +- break; ++ ++ goto done; + } + /* TODO Back-off. */ + } + +- /* We are the primary writer; enable blocking on __writers_futex. Relaxed +- MO is sufficient for futex words; acquire MO on the previous +- modifications of __readers ensures that this store happens after the +- store of value 0 by the previous primary writer. */ +- atomic_store_relaxed (&rwlock->__data.__writers_futex, +- 1 | (may_share_futex_used_flag ? PTHREAD_RWLOCK_FUTEX_USED : 0)); +- +- if (__glibc_unlikely ((r & PTHREAD_RWLOCK_WRPHASE) == 0)) ++ /* We became the primary writer in a read phase and there were readers when ++ we did (because of the previous loop). Thus, we have to wait for ++ explicit hand-over from one of these readers. ++ We basically do the same steps as for the similar case in ++ __pthread_rwlock_rdlock_full, except that we additionally might try ++ to directly hand over to another writer and need to wake up ++ other writers or waiting readers (i.e., PTHREAD_RWLOCK_RWAITING). */ ++ unsigned int wpf; ++ bool ready = false; ++ for (;;) + { +- /* We are not in a read phase and there are readers (because of the +- previous loop). Thus, we have to wait for explicit hand-over from +- one of these readers. +- We basically do the same steps as for the similar case in +- __pthread_rwlock_rdlock_full, except that we additionally might try +- to directly hand over to another writer and need to wake up +- other writers or waiting readers (i.e., PTHREAD_RWLOCK_RWAITING). */ +- unsigned int wpf; +- bool ready = false; +- for (;;) ++ while (((wpf = atomic_load_relaxed (&rwlock->__data.__wrphase_futex)) ++ | PTHREAD_RWLOCK_FUTEX_USED) == PTHREAD_RWLOCK_FUTEX_USED) + { +- while (((wpf = atomic_load_relaxed (&rwlock->__data.__wrphase_futex)) +- | PTHREAD_RWLOCK_FUTEX_USED) == PTHREAD_RWLOCK_FUTEX_USED) ++ int private = __pthread_rwlock_get_private (rwlock); ++ if (((wpf & PTHREAD_RWLOCK_FUTEX_USED) == 0) ++ && !atomic_compare_exchange_weak_relaxed ++ (&rwlock->__data.__wrphase_futex, &wpf, ++ PTHREAD_RWLOCK_FUTEX_USED)) ++ continue; ++ int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex, ++ PTHREAD_RWLOCK_FUTEX_USED, abstime, private); ++ if (err == ETIMEDOUT) + { +- int private = __pthread_rwlock_get_private (rwlock); +- if (((wpf & PTHREAD_RWLOCK_FUTEX_USED) == 0) +- && !atomic_compare_exchange_weak_relaxed +- (&rwlock->__data.__wrphase_futex, &wpf, +- PTHREAD_RWLOCK_FUTEX_USED)) +- continue; +- int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex, +- PTHREAD_RWLOCK_FUTEX_USED, abstime, private); +- if (err == ETIMEDOUT) ++ if (rwlock->__data.__flags ++ != PTHREAD_RWLOCK_PREFER_READER_NP) + { +- if (rwlock->__data.__flags +- != PTHREAD_RWLOCK_PREFER_READER_NP) +- { +- /* We try writer--writer hand-over. */ +- unsigned int w = atomic_load_relaxed +- (&rwlock->__data.__writers); +- if (w != 0) +- { +- /* We are about to hand over WRLOCKED, so we must +- release __writers_futex too; otherwise, we'd have +- a pending store, which could at least prevent +- other threads from waiting using the futex +- because it could interleave with the stores +- by subsequent writers. In turn, this means that +- we have to clean up when we do not hand over +- WRLOCKED. +- Release MO so that another writer that gets +- WRLOCKED from us can take over our view of +- __readers. */ +- unsigned int wf = atomic_exchange_relaxed +- (&rwlock->__data.__writers_futex, 0); +- while (w != 0) +- { +- if (atomic_compare_exchange_weak_release +- (&rwlock->__data.__writers, &w, +- w | PTHREAD_RWLOCK_WRHANDOVER)) +- { +- /* Wake other writers. */ +- if ((wf & PTHREAD_RWLOCK_FUTEX_USED) != 0) +- futex_wake +- (&rwlock->__data.__writers_futex, 1, +- private); +- return ETIMEDOUT; +- } +- /* TODO Back-off. */ +- } +- /* We still own WRLOCKED and someone else might set +- a write phase concurrently, so enable waiting +- again. Make sure we don't loose the flag that +- signals whether there are threads waiting on +- this futex. */ +- atomic_store_relaxed +- (&rwlock->__data.__writers_futex, wf); +- } +- } +- /* If we timed out and we are not in a write phase, we can +- just stop being a primary writer. Otherwise, we just +- acquire the lock. */ +- r = atomic_load_relaxed (&rwlock->__data.__readers); +- if ((r & PTHREAD_RWLOCK_WRPHASE) == 0) ++ /* We try writer--writer hand-over. */ ++ unsigned int w = atomic_load_relaxed ++ (&rwlock->__data.__writers); ++ if (w != 0) + { +- /* We are about to release WRLOCKED, so we must release +- __writers_futex too; see the handling of +- writer--writer hand-over above. */ ++ /* We are about to hand over WRLOCKED, so we must ++ release __writers_futex too; otherwise, we'd have ++ a pending store, which could at least prevent ++ other threads from waiting using the futex ++ because it could interleave with the stores ++ by subsequent writers. In turn, this means that ++ we have to clean up when we do not hand over ++ WRLOCKED. ++ Release MO so that another writer that gets ++ WRLOCKED from us can take over our view of ++ __readers. */ + unsigned int wf = atomic_exchange_relaxed + (&rwlock->__data.__writers_futex, 0); +- while ((r & PTHREAD_RWLOCK_WRPHASE) == 0) ++ while (w != 0) + { +- /* While we don't need to make anything from a +- caller's critical section visible to other +- threads, we need to ensure that our changes to +- __writers_futex are properly ordered. +- Therefore, use release MO to synchronize with +- subsequent primary writers. Also wake up any +- waiting readers as they are waiting because of +- us. */ + if (atomic_compare_exchange_weak_release +- (&rwlock->__data.__readers, &r, +- (r ^ PTHREAD_RWLOCK_WRLOCKED) +- & ~(unsigned int) PTHREAD_RWLOCK_RWAITING)) ++ (&rwlock->__data.__writers, &w, ++ w | PTHREAD_RWLOCK_WRHANDOVER)) + { + /* Wake other writers. */ + if ((wf & PTHREAD_RWLOCK_FUTEX_USED) != 0) + futex_wake (&rwlock->__data.__writers_futex, +- 1, private); +- /* Wake waiting readers. */ +- if ((r & PTHREAD_RWLOCK_RWAITING) != 0) +- futex_wake (&rwlock->__data.__readers, +- INT_MAX, private); ++ 1, private); + return ETIMEDOUT; + } ++ /* TODO Back-off. */ + } +- /* We still own WRLOCKED and someone else might set a +- write phase concurrently, so enable waiting again. +- Make sure we don't loose the flag that signals +- whether there are threads waiting on this futex. */ +- atomic_store_relaxed (&rwlock->__data.__writers_futex, +- wf); ++ /* We still own WRLOCKED and someone else might set ++ a write phase concurrently, so enable waiting ++ again. Make sure we don't loose the flag that ++ signals whether there are threads waiting on ++ this futex. */ ++ atomic_store_relaxed ++ (&rwlock->__data.__writers_futex, wf); + } +- /* Use the acquire MO fence to mirror the steps taken in the +- non-timeout case. Note that the read can happen both +- in the atomic_load above as well as in the failure case +- of the CAS operation. */ +- atomic_thread_fence_acquire (); +- /* We still need to wait for explicit hand-over, but we must +- not use futex_wait anymore. */ +- while ((atomic_load_relaxed +- (&rwlock->__data.__wrphase_futex) +- | PTHREAD_RWLOCK_FUTEX_USED) +- == PTHREAD_RWLOCK_FUTEX_USED) ++ } ++ /* If we timed out and we are not in a write phase, we can ++ just stop being a primary writer. Otherwise, we just ++ acquire the lock. */ ++ r = atomic_load_relaxed (&rwlock->__data.__readers); ++ if ((r & PTHREAD_RWLOCK_WRPHASE) == 0) ++ { ++ /* We are about to release WRLOCKED, so we must release ++ __writers_futex too; see the handling of ++ writer--writer hand-over above. */ ++ unsigned int wf = atomic_exchange_relaxed ++ (&rwlock->__data.__writers_futex, 0); ++ while ((r & PTHREAD_RWLOCK_WRPHASE) == 0) + { +- /* TODO Back-off. */ ++ /* While we don't need to make anything from a ++ caller's critical section visible to other ++ threads, we need to ensure that our changes to ++ __writers_futex are properly ordered. ++ Therefore, use release MO to synchronize with ++ subsequent primary writers. Also wake up any ++ waiting readers as they are waiting because of ++ us. */ ++ if (atomic_compare_exchange_weak_release ++ (&rwlock->__data.__readers, &r, ++ (r ^ PTHREAD_RWLOCK_WRLOCKED) ++ & ~(unsigned int) PTHREAD_RWLOCK_RWAITING)) ++ { ++ /* Wake other writers. */ ++ if ((wf & PTHREAD_RWLOCK_FUTEX_USED) != 0) ++ futex_wake (&rwlock->__data.__writers_futex, ++ 1, private); ++ /* Wake waiting readers. */ ++ if ((r & PTHREAD_RWLOCK_RWAITING) != 0) ++ futex_wake (&rwlock->__data.__readers, ++ INT_MAX, private); ++ return ETIMEDOUT; ++ } + } +- ready = true; +- break; ++ /* We still own WRLOCKED and someone else might set a ++ write phase concurrently, so enable waiting again. ++ Make sure we don't loose the flag that signals ++ whether there are threads waiting on this futex. */ ++ atomic_store_relaxed (&rwlock->__data.__writers_futex, wf); + } +- /* If we got interrupted (EINTR) or the futex word does not have +- the expected value (EAGAIN), retry. */ ++ /* Use the acquire MO fence to mirror the steps taken in the ++ non-timeout case. Note that the read can happen both ++ in the atomic_load above as well as in the failure case ++ of the CAS operation. */ ++ atomic_thread_fence_acquire (); ++ /* We still need to wait for explicit hand-over, but we must ++ not use futex_wait anymore. */ ++ while ((atomic_load_relaxed ++ (&rwlock->__data.__wrphase_futex) ++ | PTHREAD_RWLOCK_FUTEX_USED) ++ == PTHREAD_RWLOCK_FUTEX_USED) ++ { ++ /* TODO Back-off. */ ++ } ++ ready = true; ++ break; + } +- /* See pthread_rwlock_rdlock_full. */ +- if (ready) +- break; +- if ((atomic_load_acquire (&rwlock->__data.__readers) +- & PTHREAD_RWLOCK_WRPHASE) != 0) +- ready = true; ++ /* If we got interrupted (EINTR) or the futex word does not have ++ the expected value (EAGAIN), retry. */ + } ++ /* See pthread_rwlock_rdlock_full. */ ++ if (ready) ++ break; ++ if ((atomic_load_acquire (&rwlock->__data.__readers) ++ & PTHREAD_RWLOCK_WRPHASE) != 0) ++ ready = true; + } + ++ done: + atomic_store_relaxed (&rwlock->__data.__cur_writer, + THREAD_GETMEM (THREAD_SELF, tid)); + return 0; +diff --git a/nptl/tst-compat-forwarder-mod.c b/nptl/tst-compat-forwarder-mod.c +new file mode 100644 +index 0000000000..823bfa22de +--- /dev/null ++++ b/nptl/tst-compat-forwarder-mod.c +@@ -0,0 +1,28 @@ ++/* Copyright (C) 2017 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 ++ . */ ++ ++/* Call the function system through a statically initialized pointer. */ ++ ++#include ++ ++int (*system_function) (const char *) = system; ++ ++void ++call_system (void) ++{ ++ system_function (NULL); ++} +diff --git a/nptl/tst-compat-forwarder.c b/nptl/tst-compat-forwarder.c +new file mode 100644 +index 0000000000..f96806b7fe +--- /dev/null ++++ b/nptl/tst-compat-forwarder.c +@@ -0,0 +1,35 @@ ++/* Copyright (C) 2017 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 ++ . */ ++ ++/* Test that the compat forwaders in libpthread work correctly. */ ++ ++#include ++ ++extern void call_system (void); ++ ++int ++do_test (void) ++{ ++ /* Calling the system function from a shared library that is not linked ++ against libpthread, when the main program is linked against ++ libpthread, should not crash. */ ++ call_system (); ++ ++ return 0; ++} ++ ++#include +diff --git a/nptl/tst-mutex7.c b/nptl/tst-mutex7.c +index a11afdba5e..08fe251eeb 100644 +--- a/nptl/tst-mutex7.c ++++ b/nptl/tst-mutex7.c +@@ -22,25 +22,41 @@ + #include + #include + +- ++/* This test is a template for other tests to use. Other tests define ++ the following macros to change the behaviour of the template test. ++ The test is very simple, it configures N threads given the parameters ++ below and then proceeds to go through mutex lock and unlock ++ operations in each thread as described before for the thread ++ function. */ + #ifndef TYPE + # define TYPE PTHREAD_MUTEX_DEFAULT + #endif +- ++#ifndef ROBUST ++# define ROBUST PTHREAD_MUTEX_STALLED ++#endif ++#ifndef DELAY_NSEC ++# define DELAY_NSEC 11000 ++#endif ++#ifndef ROUNDS ++# define ROUNDS 1000 ++#endif ++#ifndef N ++# define N 100 ++#endif + + static pthread_mutex_t lock; + +- +-#define ROUNDS 1000 +-#define N 100 +- +- ++/* Each thread locks and the subsequently unlocks the lock, yielding ++ the smallest critical section possible. After the unlock the thread ++ waits DELAY_NSEC nanoseconds before doing the lock and unlock again. ++ Every thread does this ROUNDS times. The lock and unlock are ++ checked for errors. */ + static void * + tf (void *arg) + { + int nr = (long int) arg; + int cnt; +- struct timespec ts = { .tv_sec = 0, .tv_nsec = 11000 }; ++ struct timespec ts = { .tv_sec = 0, .tv_nsec = DELAY_NSEC }; + + for (cnt = 0; cnt < ROUNDS; ++cnt) + { +@@ -56,13 +72,16 @@ tf (void *arg) + return (void *) 1l; + } + +- nanosleep (&ts, NULL); ++ if ((ts.tv_sec > 0) || (ts.tv_nsec > 0)) ++ nanosleep (&ts, NULL); + } + + return NULL; + } + +- ++/* Setup and run N threads, where each thread does as described ++ in the above thread function. The threads are given a minimal 1MiB ++ stack since they don't do anything between the lock and unlock. */ + static int + do_test (void) + { +@@ -80,6 +99,12 @@ do_test (void) + exit (1); + } + ++ if (pthread_mutexattr_setrobust (&a, ROBUST) != 0) ++ { ++ puts ("mutexattr_setrobust failed"); ++ exit (1); ++ } ++ + #ifdef ENABLE_PI + if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT) != 0) + { +diff --git a/nptl/tst-mutex7robust.c b/nptl/tst-mutex7robust.c +new file mode 100644 +index 0000000000..8221a61d29 +--- /dev/null ++++ b/nptl/tst-mutex7robust.c +@@ -0,0 +1,7 @@ ++/* Bug 21778: Fix oversight in robust mutex lock acquisition. */ ++#define TYPE PTHREAD_MUTEX_NORMAL ++#define ROBUST PTHREAD_MUTEX_ROBUST ++#define DELAY_NSEC 0 ++#define ROUNDS 1000 ++#define N 32 ++#include "tst-mutex7.c" +diff --git a/nptl/tst-rwlock20.c b/nptl/tst-rwlock20.c +new file mode 100644 +index 0000000000..4aeea2b8f5 +--- /dev/null ++++ b/nptl/tst-rwlock20.c +@@ -0,0 +1,116 @@ ++/* Test program for a read-phase / write-phase explicit hand-over. ++ Copyright (C) 2017 Free Software Foundation, Inc. ++ ++ 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; see the file COPYING.LIB. If ++ not, see . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* We realy want to set threads to 2 to reproduce this issue. The goal ++ is to have one primary writer and a single reader, and to hit the ++ bug that happens in the interleaving of those two phase transitions. ++ However, on most hardware, adding a second writer seems to help the ++ interleaving happen slightly more often, say 20% of the time. On a ++ 16 core ppc64 machine this fails 100% of the time with an unpatched ++ glibc. On a 8 core x86_64 machine this fails ~93% of the time, but ++ it doesn't fail at all on a 4 core system, so having available ++ unloaded cores makes a big difference in reproducibility. On an 8 ++ core qemu/kvm guest the reproducer reliability drops to ~10%. */ ++#define THREADS 3 ++ ++#define KIND PTHREAD_RWLOCK_PREFER_READER_NP ++ ++static pthread_rwlock_t lock; ++static int done = 0; ++ ++static void* ++tf (void* arg) ++{ ++ while (atomic_load_relaxed (&done) == 0) ++ { ++ int rcnt = 0; ++ int wcnt = 100; ++ if ((uintptr_t) arg == 0) ++ { ++ rcnt = 1; ++ wcnt = 1; ++ } ++ ++ do ++ { ++ if (wcnt) ++ { ++ xpthread_rwlock_wrlock (&lock); ++ xpthread_rwlock_unlock (&lock); ++ wcnt--; ++ } ++ if (rcnt) ++ { ++ xpthread_rwlock_rdlock (&lock); ++ xpthread_rwlock_unlock (&lock); ++ rcnt--; ++ } ++ } ++ while ((atomic_load_relaxed (&done) == 0) && (rcnt + wcnt > 0)); ++ ++ } ++ return NULL; ++} ++ ++ ++ ++static int ++do_test (void) ++{ ++ pthread_t thr[THREADS]; ++ int n; ++ pthread_rwlockattr_t attr; ++ ++ xpthread_rwlockattr_init (&attr); ++ xpthread_rwlockattr_setkind_np (&attr, KIND); ++ ++ xpthread_rwlock_init (&lock, &attr); ++ ++ /* Make standard error the same as standard output. */ ++ dup2 (1, 2); ++ ++ /* Make sure we see all message, even those on stdout. */ ++ setvbuf (stdout, NULL, _IONBF, 0); ++ ++ for (n = 0; n < THREADS; ++n) ++ thr[n] = xpthread_create (NULL, tf, (void *) (uintptr_t) n); ++ ++ struct timespec delay; ++ delay.tv_sec = 10; ++ delay.tv_nsec = 0; ++ nanosleep (&delay, NULL); ++ atomic_store_relaxed (&done, 1); ++ ++ /* Wait for all the threads. */ ++ for (n = 0; n < THREADS; ++n) ++ xpthread_join (thr[n]); ++ ++ return 0; ++} ++ ++#include +diff --git a/posix/Makefile b/posix/Makefile +index 8f23d647c8..ccbfcf3c48 100644 +--- a/posix/Makefile ++++ b/posix/Makefile +@@ -43,7 +43,7 @@ routines := \ + getpgid setpgid getpgrp bsd-getpgrp setpgrp getsid setsid \ + getresuid getresgid setresuid setresgid \ + pathconf sysconf fpathconf \ +- glob glob64 fnmatch regex \ ++ glob glob64 globfree globfree64 glob_pattern_p fnmatch regex \ + confstr \ + getopt getopt1 getopt_init \ + sched_setp sched_getp sched_sets sched_gets sched_yield sched_primax \ +@@ -91,7 +91,8 @@ tests := tstgetopt testfnm runtests runptests \ + tst-pathconf tst-getaddrinfo4 tst-rxspencer-no-utf8 \ + tst-fnmatch3 bug-regex36 tst-getaddrinfo5 \ + tst-posix_spawn-fd \ +- tst-posix_fadvise tst-posix_fadvise64 ++ tst-posix_fadvise tst-posix_fadvise64 \ ++ tst-glob-tilde + xtests := bug-ga2 + ifeq (yes,$(build-shared)) + test-srcs := globtest +@@ -134,7 +135,8 @@ tests-special += $(objpfx)bug-regex2-mem.out $(objpfx)bug-regex14-mem.out \ + $(objpfx)tst-rxspencer-no-utf8-mem.out $(objpfx)tst-pcre-mem.out \ + $(objpfx)tst-boost-mem.out $(objpfx)tst-getconf.out \ + $(objpfx)bug-glob2-mem.out $(objpfx)tst-vfork3-mem.out \ +- $(objpfx)tst-fnmatch-mem.out $(objpfx)bug-regex36-mem.out ++ $(objpfx)tst-fnmatch-mem.out $(objpfx)bug-regex36-mem.out \ ++ $(objpfx)tst-glob-tilde-mem.out + xtests-special += $(objpfx)bug-ga2-mem.out + endif + +@@ -341,6 +343,12 @@ $(objpfx)bug-glob2-mem.out: $(objpfx)bug-glob2.out + $(common-objpfx)malloc/mtrace $(objpfx)bug-glob2.mtrace > $@; \ + $(evaluate-test) + ++tst-glob-tilde-ENV = MALLOC_TRACE=$(objpfx)tst-glob-tilde.mtrace ++ ++$(objpfx)tst-glob-tilde-mem.out: $(objpfx)tst-glob-tilde.out ++ $(common-objpfx)malloc/mtrace $(objpfx)tst-glob-tilde.mtrace > $@; \ ++ $(evaluate-test) ++ + $(inst_libexecdir)/getconf: $(inst_bindir)/getconf \ + $(objpfx)getconf.speclist FORCE + $(addprefix $(..)./scripts/mkinstalldirs ,\ +diff --git a/posix/flexmember.h b/posix/flexmember.h +new file mode 100644 +index 0000000000..107c1f09e9 +--- /dev/null ++++ b/posix/flexmember.h +@@ -0,0 +1,45 @@ ++/* Sizes of structs with flexible array members. ++ ++ Copyright 2016-2017 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 ++ . ++ ++ Written by Paul Eggert. */ ++ ++#include ++ ++/* Nonzero multiple of alignment of TYPE, suitable for FLEXSIZEOF below. ++ On older platforms without _Alignof, use a pessimistic bound that is ++ safe in practice even if FLEXIBLE_ARRAY_MEMBER is 1. ++ On newer platforms, use _Alignof to get a tighter bound. */ ++ ++#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112 ++# define FLEXALIGNOF(type) (sizeof (type) & ~ (sizeof (type) - 1)) ++#else ++# define FLEXALIGNOF(type) _Alignof (type) ++#endif ++ ++/* Upper bound on the size of a struct of type TYPE with a flexible ++ array member named MEMBER that is followed by N bytes of other data. ++ This is not simply sizeof (TYPE) + N, since it may require ++ alignment on unusually picky C11 platforms, and ++ FLEXIBLE_ARRAY_MEMBER may be 1 on pre-C11 platforms. ++ Yield a value less than N if and only if arithmetic overflow occurs. */ ++ ++#define FLEXSIZEOF(type, member, n) \ ++ ((offsetof (type, member) + FLEXALIGNOF (type) - 1 + (n)) \ ++ & ~ (FLEXALIGNOF (type) - 1)) +diff --git a/posix/glob.c b/posix/glob.c +index c653809118..b2273ea7bc 100644 +--- a/posix/glob.c ++++ b/posix/glob.c +@@ -15,7 +15,7 @@ + License along with the GNU C Library; if not, see + . */ + +-#ifdef HAVE_CONFIG_H ++#ifndef _LIBC + # include + #endif + +@@ -27,29 +27,15 @@ + #include + #include + #include +- +-/* Outcomment the following line for production quality code. */ +-/* #define NDEBUG 1 */ + #include ++#include + +-#include /* Needed on stupid SunOS for assert. */ +- +-#if !defined _LIBC || !defined GLOB_ONLY_P +-#if defined HAVE_UNISTD_H || defined _LIBC +-# include +-# ifndef POSIX +-# ifdef _POSIX_VERSION +-# define POSIX +-# endif +-# endif ++#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ ++# define WINDOWS32 + #endif + +-#include +- +-#if defined HAVE_STDINT_H || defined _LIBC +-# include +-#elif !defined UINTPTR_MAX +-# define UINTPTR_MAX (~((size_t) 0)) ++#ifndef WINDOWS32 ++# include + #endif + + #include +@@ -57,24 +43,7 @@ + # define __set_errno(val) errno = (val) + #endif + +-#if defined HAVE_DIRENT_H || defined __GNU_LIBRARY__ +-# include +-#else +-# define dirent direct +-# ifdef HAVE_SYS_NDIR_H +-# include +-# endif +-# ifdef HAVE_SYS_DIR_H +-# include +-# endif +-# ifdef HAVE_NDIR_H +-# include +-# endif +-# ifdef HAVE_VMSDIR_H +-# include "vmsdir.h" +-# endif /* HAVE_VMSDIR_H */ +-#endif +- ++#include + #include + #include + #include +@@ -87,27 +56,29 @@ + # define opendir(name) __opendir (name) + # define readdir(str) __readdir64 (str) + # define getpwnam_r(name, bufp, buf, len, res) \ +- __getpwnam_r (name, bufp, buf, len, res) ++ __getpwnam_r (name, bufp, buf, len, res) + # ifndef __stat64 + # define __stat64(fname, buf) __xstat64 (_STAT_VER, fname, buf) + # endif + # define struct_stat64 struct stat64 ++# define FLEXIBLE_ARRAY_MEMBER + #else /* !_LIBC */ +-# include "getlogin_r.h" +-# include "mempcpy.h" +-# include "stat-macros.h" +-# include "strdup.h" +-# define __stat64(fname, buf) stat (fname, buf) +-# define struct_stat64 struct stat +-# define __stat(fname, buf) stat (fname, buf) +-# define __alloca alloca +-# define __readdir readdir +-# define __readdir64 readdir64 +-# define __glob_pattern_p glob_pattern_p ++# define __getlogin_r(buf, len) getlogin_r (buf, len) ++# define __stat64(fname, buf) stat (fname, buf) ++# define __fxstatat64(_, d, f, st, flag) fstatat (d, f, st, flag) ++# define struct_stat64 struct stat ++# ifndef __MVS__ ++# define __alloca alloca ++# endif ++# define __readdir readdir ++# define COMPILE_GLOB64 + #endif /* _LIBC */ + + #include + ++#include ++#include ++ + #ifdef _SC_GETPW_R_SIZE_MAX + # define GETPW_R_SIZE_MAX() sysconf (_SC_GETPW_R_SIZE_MAX) + #else +@@ -121,61 +92,59 @@ + + static const char *next_brace_sub (const char *begin, int flags) __THROWNL; + ++typedef uint_fast8_t dirent_type; ++ ++#if !defined _LIBC && !defined HAVE_STRUCT_DIRENT_D_TYPE ++/* Any distinct values will do here. ++ Undef any existing macros out of the way. */ ++# undef DT_UNKNOWN ++# undef DT_DIR ++# undef DT_LNK ++# define DT_UNKNOWN 0 ++# define DT_DIR 1 ++# define DT_LNK 2 ++#endif ++ + /* A representation of a directory entry which does not depend on the + layout of struct dirent, or the size of ino_t. */ + struct readdir_result + { + const char *name; +-# if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE +- uint8_t type; +-# endif ++#if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE ++ dirent_type type; ++#endif ++#if defined _LIBC || defined D_INO_IN_DIRENT + bool skip_entry; ++#endif + }; + +-# if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE +-/* Initializer based on the d_type member of struct dirent. */ +-# define D_TYPE_TO_RESULT(source) (source)->d_type, +- +-/* True if the directory entry D might be a symbolic link. */ +-static bool +-readdir_result_might_be_symlink (struct readdir_result d) +-{ +- return d.type == DT_UNKNOWN || d.type == DT_LNK; +-} +- +-/* True if the directory entry D might be a directory. */ +-static bool +-readdir_result_might_be_dir (struct readdir_result d) +-{ +- return d.type == DT_DIR || readdir_result_might_be_symlink (d); +-} +-# else /* defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE */ +-# define D_TYPE_TO_RESULT(source) +- +-/* If we do not have type information, symbolic links and directories +- are always a possibility. */ +- +-static bool +-readdir_result_might_be_symlink (struct readdir_result d) ++/* Initialize and return type member of struct readdir_result. */ ++static dirent_type ++readdir_result_type (struct readdir_result d) + { +- return true; ++#if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE ++# define D_TYPE_TO_RESULT(source) (source)->d_type, ++ return d.type; ++#else ++# define D_TYPE_TO_RESULT(source) ++ return DT_UNKNOWN; ++#endif + } + ++/* Initialize and return skip_entry member of struct readdir_result. */ + static bool +-readdir_result_might_be_dir (struct readdir_result d) ++readdir_result_skip_entry (struct readdir_result d) + { +- return true; +-} +- +-# endif /* defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE */ +- +-# if (defined POSIX || defined WINDOWS32) && !defined __GNU_LIBRARY__ + /* Initializer for skip_entry. POSIX does not require that the d_ino + field be present, and some systems do not provide it. */ +-# define D_INO_TO_RESULT(source) false, +-# else +-# define D_INO_TO_RESULT(source) (source)->d_ino == 0, +-# endif ++#if defined _LIBC || defined D_INO_IN_DIRENT ++# define D_INO_TO_RESULT(source) (source)->d_ino == 0, ++ return d.skip_entry; ++#else ++# define D_INO_TO_RESULT(source) ++ return false; ++#endif ++} + + /* Construct an initializer for a struct readdir_result object from a + struct dirent *. No copy of the name is made. */ +@@ -186,8 +155,6 @@ readdir_result_might_be_dir (struct readdir_result d) + D_INO_TO_RESULT (source) \ + } + +-#endif /* !defined _LIBC || !defined GLOB_ONLY_P */ +- + /* Call gl_readdir on STREAM. This macro can be overridden to reduce + type safety if an old interface version needs to be supported. */ + #ifndef GL_READDIR +@@ -225,18 +192,55 @@ convert_dirent64 (const struct dirent64 *source) + } + #endif + ++#ifndef _LIBC ++/* The results of opendir() in this file are not used with dirfd and fchdir, ++ and we do not leak fds to any single-threaded code that could use stdio, ++ therefore save some unnecessary recursion in fchdir.c and opendir_safer.c. ++ FIXME - if the kernel ever adds support for multi-thread safety for ++ avoiding standard fds, then we should use opendir_safer. */ ++# ifdef GNULIB_defined_opendir ++# undef opendir ++# endif ++# ifdef GNULIB_defined_closedir ++# undef closedir ++# endif + +-#ifndef attribute_hidden +-# define attribute_hidden ++/* Just use malloc. */ ++# define __libc_use_alloca(n) false ++# define alloca_account(len, avar) ((void) (len), (void) (avar), (void *) 0) ++# define extend_alloca_account(buf, len, newlen, avar) \ ++ ((void) (buf), (void) (len), (void) (newlen), (void) (avar), (void *) 0) + #endif + ++/* Set *R = A + B. Return true if the answer is mathematically ++ incorrect due to overflow; in this case, *R is the low order ++ bits of the correct answer. */ ++ ++static bool ++size_add_wrapv (size_t a, size_t b, size_t *r) ++{ ++#if 5 <= __GNUC__ && !defined __ICC ++ return __builtin_add_overflow (a, b, r); ++#else ++ *r = a + b; ++ return *r < a; ++#endif ++} ++ ++static bool ++glob_use_alloca (size_t alloca_used, size_t len) ++{ ++ size_t size; ++ return (!size_add_wrapv (alloca_used, len, &size) ++ && __libc_use_alloca (size)); ++} ++ + static int glob_in_dir (const char *pattern, const char *directory, + int flags, int (*errfunc) (const char *, int), + glob_t *pglob, size_t alloca_used); + extern int __glob_pattern_type (const char *pattern, int quote) + attribute_hidden; + +-#if !defined _LIBC || !defined GLOB_ONLY_P + static int prefix_array (const char *prefix, char **array, size_t n) __THROWNL; + static int collated_compare (const void *, const void *) __THROWNL; + +@@ -265,16 +269,15 @@ next_brace_sub (const char *cp, int flags) + return *cp != '\0' ? cp : NULL; + } + +-#endif /* !defined _LIBC || !defined GLOB_ONLY_P */ + + /* Do glob searching for PATTERN, placing results in PGLOB. + The bits defined above may be set in FLAGS. + If a directory cannot be opened or read and ERRFUNC is not nil, + it is called with the pathname that caused the error, and the +- `errno' value from the failing call; if it returns non-zero +- `glob' returns GLOB_ABORTED; if it returns zero, the error is ignored. ++ 'errno' value from the failing call; if it returns non-zero ++ 'glob' returns GLOB_ABORTED; if it returns zero, the error is ignored. + If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned. +- Otherwise, `glob' returns zero. */ ++ Otherwise, 'glob' returns zero. */ + int + #ifdef GLOB_ATTRIBUTE + GLOB_ATTRIBUTE +@@ -292,9 +295,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), + int malloc_dirname = 0; + glob_t dirs; + int retval = 0; +-#ifdef _LIBC + size_t alloca_used = 0; +-#endif + + if (pattern == NULL || pglob == NULL || (flags & ~__GLOB_FLAGS) != 0) + { +@@ -308,7 +309,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), + flags |= GLOB_ONLYDIR; + + if (!(flags & GLOB_DOOFFS)) +- /* Have to do this so `globfree' knows where to start freeing. It ++ /* Have to do this so 'globfree' knows where to start freeing. It + also makes all the code that uses gl_offs simpler. */ + pglob->gl_offs = 0; + +@@ -372,14 +373,12 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), + size_t rest_len; + char *onealt; + size_t pattern_len = strlen (pattern) - 1; +-#ifdef _LIBC +- int alloca_onealt = __libc_use_alloca (alloca_used + pattern_len); ++ int alloca_onealt = glob_use_alloca (alloca_used, pattern_len); + if (alloca_onealt) + onealt = alloca_account (pattern_len, alloca_used); + else +-#endif + { +- onealt = (char *) malloc (pattern_len); ++ onealt = malloc (pattern_len); + if (onealt == NULL) + return GLOB_NOSPACE; + } +@@ -392,11 +391,9 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), + next = next_brace_sub (begin + 1, flags); + if (next == NULL) + { +- /* It is an illegal expression. */ ++ /* It is an invalid expression. */ + illegal_brace: +-#ifdef _LIBC + if (__glibc_unlikely (!alloca_onealt)) +-#endif + free (onealt); + flags &= ~GLOB_BRACE; + goto no_brace; +@@ -437,9 +434,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), + /* If we got an error, return it. */ + if (result && result != GLOB_NOMATCH) + { +-#ifdef _LIBC + if (__glibc_unlikely (!alloca_onealt)) +-#endif + free (onealt); + if (!(flags & GLOB_APPEND)) + { +@@ -458,9 +453,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), + assert (next != NULL); + } + +-#ifdef _LIBC + if (__glibc_unlikely (!alloca_onealt)) +-#endif + free (onealt); + + if (pglob->gl_pathc != firstc) +@@ -476,14 +469,16 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), + + /* Find the filename. */ + filename = strrchr (pattern, '/'); ++ + #if defined __MSDOS__ || defined WINDOWS32 +- /* The case of "d:pattern". Since `:' is not allowed in ++ /* The case of "d:pattern". Since ':' is not allowed in + file names, we can safely assume that wherever it + happens in pattern, it signals the filename part. This + is so we could some day support patterns like "[a-z]:foo". */ + if (filename == NULL) + filename = strchr (pattern, ':'); + #endif /* __MSDOS__ || WINDOWS32 */ ++ + dirname_modified = 0; + if (filename == NULL) + { +@@ -508,11 +503,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), + } + + filename = pattern; +-#ifdef _AMIGA +- dirname = (char *) ""; +-#else + dirname = (char *) "."; +-#endif + dirlen = 0; + } + } +@@ -536,22 +527,21 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), + char *drive_spec; + + ++dirlen; +- drive_spec = (char *) __alloca (dirlen + 1); ++ drive_spec = __alloca (dirlen + 1); + *((char *) mempcpy (drive_spec, pattern, dirlen)) = '\0'; + /* For now, disallow wildcards in the drive spec, to + prevent infinite recursion in glob. */ + if (__glob_pattern_p (drive_spec, !(flags & GLOB_NOESCAPE))) + return GLOB_NOMATCH; +- /* If this is "d:pattern", we need to copy `:' to DIRNAME ++ /* If this is "d:pattern", we need to copy ':' to DIRNAME + as well. If it's "d:/pattern", don't remove the slash + from "d:/", since "d:" and "d:/" are not the same.*/ + } + #endif +-#ifdef _LIBC +- if (__libc_use_alloca (alloca_used + dirlen + 1)) ++ ++ if (glob_use_alloca (alloca_used, dirlen + 1)) + newp = alloca_account (dirlen + 1, alloca_used); + else +-#endif + { + newp = malloc (dirlen + 1); + if (newp == NULL) +@@ -562,14 +552,17 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), + dirname = newp; + ++filename; + +- if (filename[0] == '\0' + #if defined __MSDOS__ || defined WINDOWS32 +- && dirname[dirlen - 1] != ':' +- && (dirlen < 3 || dirname[dirlen - 2] != ':' +- || dirname[dirlen - 1] != '/') ++ bool drive_root = (dirlen > 1 ++ && (dirname[dirlen - 1] == ':' ++ || (dirlen > 2 && dirname[dirlen - 2] == ':' ++ && dirname[dirlen - 1] == '/'))); ++#else ++ bool drive_root = false; + #endif +- && dirlen > 1) +- /* "pattern/". Expand "pattern", appending slashes. */ ++ ++ if (filename[0] == '\0' && dirlen > 1 && !drive_root) ++ /* "pattern/". Expand "pattern", appending slashes. */ + { + int orig_flags = flags; + if (!(flags & GLOB_NOESCAPE) && dirname[dirlen - 1] == '\\') +@@ -602,7 +595,6 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), + } + } + +-#ifndef VMS + if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && dirname[0] == '~') + { + if (dirname[1] == '\0' || dirname[1] == '/' +@@ -612,100 +604,127 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), + /* Look up home directory. */ + char *home_dir = getenv ("HOME"); + int malloc_home_dir = 0; +-# ifdef _AMIGA +- if (home_dir == NULL || home_dir[0] == '\0') +- home_dir = "SYS:"; +-# else +-# ifdef WINDOWS32 +- if (home_dir == NULL || home_dir[0] == '\0') +- home_dir = "c:/users/default"; /* poor default */ +-# else + if (home_dir == NULL || home_dir[0] == '\0') + { ++#ifdef WINDOWS32 ++ /* Windows NT defines HOMEDRIVE and HOMEPATH. But give ++ preference to HOME, because the user can change HOME. */ ++ const char *home_drive = getenv ("HOMEDRIVE"); ++ const char *home_path = getenv ("HOMEPATH"); ++ ++ if (home_drive != NULL && home_path != NULL) ++ { ++ size_t home_drive_len = strlen (home_drive); ++ size_t home_path_len = strlen (home_path); ++ char *mem = alloca (home_drive_len + home_path_len + 1); ++ ++ memcpy (mem, home_drive, home_drive_len); ++ memcpy (mem + home_drive_len, home_path, home_path_len + 1); ++ home_dir = mem; ++ } ++ else ++ home_dir = "c:/users/default"; /* poor default */ ++#else + int success; + char *name; ++ int malloc_name = 0; + size_t buflen = GET_LOGIN_NAME_MAX () + 1; + + if (buflen == 0) +- /* `sysconf' does not support _SC_LOGIN_NAME_MAX. Try ++ /* 'sysconf' does not support _SC_LOGIN_NAME_MAX. Try + a moderate value. */ + buflen = 20; +- name = alloca_account (buflen, alloca_used); ++ if (glob_use_alloca (alloca_used, buflen)) ++ name = alloca_account (buflen, alloca_used); ++ else ++ { ++ name = malloc (buflen); ++ if (name == NULL) ++ { ++ retval = GLOB_NOSPACE; ++ goto out; ++ } ++ malloc_name = 1; ++ } + + success = __getlogin_r (name, buflen) == 0; + if (success) + { + struct passwd *p; +-# if defined HAVE_GETPWNAM_R || defined _LIBC +- long int pwbuflen = GETPW_R_SIZE_MAX (); ++ char *malloc_pwtmpbuf = NULL; + char *pwtmpbuf; ++# if defined HAVE_GETPWNAM_R || defined _LIBC ++ long int pwbuflenmax = GETPW_R_SIZE_MAX (); ++ size_t pwbuflen = pwbuflenmax; + struct passwd pwbuf; +- int malloc_pwtmpbuf = 0; + int save = errno; + +-# ifndef _LIBC +- if (pwbuflen == -1) +- /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX. ++# ifndef _LIBC ++ if (! (0 < pwbuflenmax && pwbuflenmax <= SIZE_MAX)) ++ /* 'sysconf' does not support _SC_GETPW_R_SIZE_MAX. + Try a moderate value. */ + pwbuflen = 1024; +-# endif +- if (__libc_use_alloca (alloca_used + pwbuflen)) ++# endif ++ if (glob_use_alloca (alloca_used, pwbuflen)) + pwtmpbuf = alloca_account (pwbuflen, alloca_used); + else + { + pwtmpbuf = malloc (pwbuflen); + if (pwtmpbuf == NULL) + { ++ if (__glibc_unlikely (malloc_name)) ++ free (name); + retval = GLOB_NOSPACE; + goto out; + } +- malloc_pwtmpbuf = 1; ++ malloc_pwtmpbuf = pwtmpbuf; + } + + while (getpwnam_r (name, &pwbuf, pwtmpbuf, pwbuflen, &p) + != 0) + { ++ size_t newlen; ++ bool v; + if (errno != ERANGE) + { + p = NULL; + break; + } +- +- if (!malloc_pwtmpbuf +- && __libc_use_alloca (alloca_used +- + 2 * pwbuflen)) ++ v = size_add_wrapv (pwbuflen, pwbuflen, &newlen); ++ if (!v && malloc_pwtmpbuf == NULL ++ && glob_use_alloca (alloca_used, newlen)) + pwtmpbuf = extend_alloca_account (pwtmpbuf, pwbuflen, +- 2 * pwbuflen, +- alloca_used); ++ newlen, alloca_used); + else + { +- char *newp = realloc (malloc_pwtmpbuf +- ? pwtmpbuf : NULL, +- 2 * pwbuflen); ++ char *newp = (v ? NULL ++ : realloc (malloc_pwtmpbuf, newlen)); + if (newp == NULL) + { +- if (__glibc_unlikely (malloc_pwtmpbuf)) +- free (pwtmpbuf); ++ free (malloc_pwtmpbuf); ++ if (__glibc_unlikely (malloc_name)) ++ free (name); + retval = GLOB_NOSPACE; + goto out; + } +- pwtmpbuf = newp; +- pwbuflen = 2 * pwbuflen; +- malloc_pwtmpbuf = 1; ++ malloc_pwtmpbuf = pwtmpbuf = newp; + } ++ pwbuflen = newlen; + __set_errno (save); + } +-# else ++# else + p = getpwnam (name); +-# endif ++# endif ++ if (__glibc_unlikely (malloc_name)) ++ free (name); + if (p != NULL) + { +- if (!malloc_pwtmpbuf) ++ if (malloc_pwtmpbuf == NULL) + home_dir = p->pw_dir; + else + { + size_t home_dir_len = strlen (p->pw_dir) + 1; +- if (__libc_use_alloca (alloca_used + home_dir_len)) ++ if (glob_use_alloca (alloca_used, home_dir_len)) + home_dir = alloca_account (home_dir_len, + alloca_used); + else +@@ -720,26 +739,32 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), + malloc_home_dir = 1; + } + memcpy (home_dir, p->pw_dir, home_dir_len); +- +- free (pwtmpbuf); + } + } ++ free (malloc_pwtmpbuf); + } ++ else ++ { ++ if (__glibc_unlikely (malloc_name)) ++ free (name); ++ } ++#endif /* WINDOWS32 */ + } + if (home_dir == NULL || home_dir[0] == '\0') + { ++ if (__glibc_unlikely (malloc_home_dir)) ++ free (home_dir); + if (flags & GLOB_TILDE_CHECK) + { +- if (__glibc_unlikely (malloc_home_dir)) +- free (home_dir); + retval = GLOB_NOMATCH; + goto out; + } + else +- home_dir = (char *) "~"; /* No luck. */ ++ { ++ home_dir = (char *) "~"; /* No luck. */ ++ malloc_home_dir = 0; ++ } + } +-# endif /* WINDOWS32 */ +-# endif + /* Now construct the full directory. */ + if (dirname[1] == '\0') + { +@@ -754,8 +779,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), + { + char *newp; + size_t home_len = strlen (home_dir); +- int use_alloca = __libc_use_alloca (alloca_used +- + home_len + dirlen); ++ int use_alloca = glob_use_alloca (alloca_used, home_len + dirlen); + if (use_alloca) + newp = alloca_account (home_len + dirlen, alloca_used); + else +@@ -779,12 +803,15 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), + dirname = newp; + dirlen += home_len - 1; + malloc_dirname = !use_alloca; ++ ++ if (__glibc_unlikely (malloc_home_dir)) ++ free (home_dir); + } + dirname_modified = 1; + } +-# if !defined _AMIGA && !defined WINDOWS32 + else + { ++#ifndef WINDOWS32 + char *end_name = strchr (dirname, '/'); + char *user_name; + int malloc_user_name = 0; +@@ -806,7 +833,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), + else + { + char *newp; +- if (__libc_use_alloca (alloca_used + (end_name - dirname))) ++ if (glob_use_alloca (alloca_used, end_name - dirname)) + newp = alloca_account (end_name - dirname, alloca_used); + else + { +@@ -823,11 +850,11 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), + char *p = mempcpy (newp, dirname + 1, + unescape - dirname - 1); + char *q = unescape; +- while (*q != '\0') ++ while (q != end_name) + { + if (*q == '\\') + { +- if (q[1] == '\0') ++ if (q + 1 == end_name) + { + /* "~fo\\o\\" unescape to user_name "foo\\", + but "~fo\\o\\/" unescape to user_name +@@ -843,7 +870,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), + *p = '\0'; + } + else +- *((char *) mempcpy (newp, dirname + 1, end_name - dirname)) ++ *((char *) mempcpy (newp, dirname + 1, end_name - dirname - 1)) + = '\0'; + user_name = newp; + } +@@ -851,20 +878,21 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), + /* Look up specific user's home directory. */ + { + struct passwd *p; ++ char *malloc_pwtmpbuf = NULL; + # if defined HAVE_GETPWNAM_R || defined _LIBC +- long int buflen = GETPW_R_SIZE_MAX (); ++ long int buflenmax = GETPW_R_SIZE_MAX (); ++ size_t buflen = buflenmax; + char *pwtmpbuf; +- int malloc_pwtmpbuf = 0; + struct passwd pwbuf; + int save = errno; + + # ifndef _LIBC +- if (buflen == -1) +- /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX. Try a ++ if (! (0 <= buflenmax && buflenmax <= SIZE_MAX)) ++ /* Perhaps 'sysconf' does not support _SC_GETPW_R_SIZE_MAX. Try a + moderate value. */ + buflen = 1024; + # endif +- if (__libc_use_alloca (alloca_used + buflen)) ++ if (glob_use_alloca (alloca_used, buflen)) + pwtmpbuf = alloca_account (buflen, alloca_used); + else + { +@@ -877,32 +905,32 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), + retval = GLOB_NOSPACE; + goto out; + } +- malloc_pwtmpbuf = 1; ++ malloc_pwtmpbuf = pwtmpbuf; + } + + while (getpwnam_r (user_name, &pwbuf, pwtmpbuf, buflen, &p) != 0) + { ++ size_t newlen; ++ bool v; + if (errno != ERANGE) + { + p = NULL; + break; + } +- if (!malloc_pwtmpbuf +- && __libc_use_alloca (alloca_used + 2 * buflen)) ++ v = size_add_wrapv (buflen, buflen, &newlen); ++ if (!v && malloc_pwtmpbuf == NULL ++ && glob_use_alloca (alloca_used, newlen)) + pwtmpbuf = extend_alloca_account (pwtmpbuf, buflen, +- 2 * buflen, alloca_used); ++ newlen, alloca_used); + else + { +- char *newp = realloc (malloc_pwtmpbuf ? pwtmpbuf : NULL, +- 2 * buflen); ++ char *newp = v ? NULL : realloc (malloc_pwtmpbuf, newlen); + if (newp == NULL) + { +- if (__glibc_unlikely (malloc_pwtmpbuf)) +- free (pwtmpbuf); ++ free (malloc_pwtmpbuf); + goto nomem_getpw; + } +- pwtmpbuf = newp; +- malloc_pwtmpbuf = 1; ++ malloc_pwtmpbuf = pwtmpbuf = newp; + } + __set_errno (save); + } +@@ -923,7 +951,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), + free (dirname); + malloc_dirname = 0; + +- if (__libc_use_alloca (alloca_used + home_len + rest_len + 1)) ++ if (glob_use_alloca (alloca_used, home_len + rest_len + 1)) + dirname = alloca_account (home_len + rest_len + 1, + alloca_used); + else +@@ -931,8 +959,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), + dirname = malloc (home_len + rest_len + 1); + if (dirname == NULL) + { +- if (__glibc_unlikely (malloc_pwtmpbuf)) +- free (pwtmpbuf); ++ free (malloc_pwtmpbuf); + retval = GLOB_NOSPACE; + goto out; + } +@@ -944,24 +971,24 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), + dirlen = home_len + rest_len; + dirname_modified = 1; + +- if (__glibc_unlikely (malloc_pwtmpbuf)) +- free (pwtmpbuf); ++ free (malloc_pwtmpbuf); + } + else + { +- if (__glibc_unlikely (malloc_pwtmpbuf)) +- free (pwtmpbuf); ++ free (malloc_pwtmpbuf); + + if (flags & GLOB_TILDE_CHECK) +- /* We have to regard it as an error if we cannot find the +- home directory. */ +- return GLOB_NOMATCH; ++ { ++ /* We have to regard it as an error if we cannot find the ++ home directory. */ ++ retval = GLOB_NOMATCH; ++ goto out; ++ } + } + } ++#endif /* !WINDOWS32 */ + } +-# endif /* Not Amiga && not WINDOWS32. */ + } +-#endif /* Not VMS. */ + + /* Now test whether we looked for "~" or "~NAME". In this case we + can give the answer now. */ +@@ -980,19 +1007,18 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), + size_t newcount = pglob->gl_pathc + pglob->gl_offs; + char **new_gl_pathv; + +- if (newcount > UINTPTR_MAX - (1 + 1) +- || newcount + 1 + 1 > ~((size_t) 0) / sizeof (char *)) ++ if (newcount > SIZE_MAX / sizeof (char *) - 2) + { + nospace: + free (pglob->gl_pathv); + pglob->gl_pathv = NULL; + pglob->gl_pathc = 0; +- return GLOB_NOSPACE; ++ retval = GLOB_NOSPACE; ++ goto out; + } + +- new_gl_pathv +- = (char **) realloc (pglob->gl_pathv, +- (newcount + 1 + 1) * sizeof (char *)); ++ new_gl_pathv = realloc (pglob->gl_pathv, ++ (newcount + 2) * sizeof (char *)); + if (new_gl_pathv == NULL) + goto nospace; + pglob->gl_pathv = new_gl_pathv; +@@ -1006,12 +1032,19 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), + p = mempcpy (pglob->gl_pathv[newcount], dirname, dirlen); + p[0] = '/'; + p[1] = '\0'; ++ if (__glibc_unlikely (malloc_dirname)) ++ free (dirname); + } + else + { +- pglob->gl_pathv[newcount] = strdup (dirname); +- if (pglob->gl_pathv[newcount] == NULL) +- goto nospace; ++ if (__glibc_unlikely (malloc_dirname)) ++ pglob->gl_pathv[newcount] = dirname; ++ else ++ { ++ pglob->gl_pathv[newcount] = strdup (dirname); ++ if (pglob->gl_pathv[newcount] == NULL) ++ goto nospace; ++ } + } + pglob->gl_pathv[++newcount] = NULL; + ++pglob->gl_pathc; +@@ -1021,7 +1054,8 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), + } + + /* Not found. */ +- return GLOB_NOMATCH; ++ retval = GLOB_NOMATCH; ++ goto out; + } + + meta = __glob_pattern_type (dirname, !(flags & GLOB_NOESCAPE)); +@@ -1067,7 +1101,10 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), + if (status != 0) + { + if ((flags & GLOB_NOCHECK) == 0 || status != GLOB_NOMATCH) +- return status; ++ { ++ retval = status; ++ goto out; ++ } + goto no_matches; + } + +@@ -1078,19 +1115,6 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), + { + size_t old_pathc; + +-#ifdef SHELL +- { +- /* Make globbing interruptible in the bash shell. */ +- extern int interrupt_state; +- +- if (interrupt_state) +- { +- globfree (&dirs); +- return GLOB_ABORTED; +- } +- } +-#endif /* SHELL. */ +- + old_pathc = pglob->gl_pathc; + status = glob_in_dir (filename, dirs.gl_pathv[i], + ((flags | GLOB_APPEND) +@@ -1105,7 +1129,8 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), + globfree (&dirs); + globfree (pglob); + pglob->gl_pathc = 0; +- return status; ++ retval = status; ++ goto out; + } + + /* Stick the directory on the front of each name. */ +@@ -1116,13 +1141,14 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), + globfree (&dirs); + globfree (pglob); + pglob->gl_pathc = 0; +- return GLOB_NOSPACE; ++ retval = GLOB_NOSPACE; ++ goto out; + } + } + + flags |= GLOB_MAGCHAR; + +- /* We have ignored the GLOB_NOCHECK flag in the `glob_in_dir' calls. ++ /* We have ignored the GLOB_NOCHECK flag in the 'glob_in_dir' calls. + But if we have not found any matching entry and the GLOB_NOCHECK + flag was set we must return the input pattern itself. */ + if (pglob->gl_pathc + pglob->gl_offs == oldcount) +@@ -1134,28 +1160,28 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), + size_t newcount = pglob->gl_pathc + pglob->gl_offs; + char **new_gl_pathv; + +- if (newcount > UINTPTR_MAX - 2 +- || newcount + 2 > ~((size_t) 0) / sizeof (char *)) ++ if (newcount > SIZE_MAX / sizeof (char *) - 2) + { + nospace2: + globfree (&dirs); +- return GLOB_NOSPACE; ++ retval = GLOB_NOSPACE; ++ goto out; + } + +- new_gl_pathv = (char **) realloc (pglob->gl_pathv, +- (newcount + 2) +- * sizeof (char *)); ++ new_gl_pathv = realloc (pglob->gl_pathv, ++ (newcount + 2) * sizeof (char *)); + if (new_gl_pathv == NULL) + goto nospace2; + pglob->gl_pathv = new_gl_pathv; + +- pglob->gl_pathv[newcount] = __strdup (pattern); ++ pglob->gl_pathv[newcount] = strdup (pattern); + if (pglob->gl_pathv[newcount] == NULL) + { + globfree (&dirs); + globfree (pglob); + pglob->gl_pathc = 0; +- return GLOB_NOSPACE; ++ retval = GLOB_NOSPACE; ++ goto out; + } + + ++pglob->gl_pathc; +@@ -1167,7 +1193,8 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), + else + { + globfree (&dirs); +- return GLOB_NOMATCH; ++ retval = GLOB_NOMATCH; ++ goto out; + } + } + +@@ -1213,7 +1240,8 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), + flags = orig_flags; + goto no_matches; + } +- return status; ++ retval = status; ++ goto out; + } + + if (dirlen > 0) +@@ -1225,7 +1253,8 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), + { + globfree (pglob); + pglob->gl_pathc = 0; +- return GLOB_NOSPACE; ++ retval = GLOB_NOSPACE; ++ goto out; + } + } + } +@@ -1250,7 +1279,8 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), + { + globfree (pglob); + pglob->gl_pathc = 0; +- return GLOB_NOSPACE; ++ retval = GLOB_NOSPACE; ++ goto out; + } + strcpy (&new[len - 2], "/"); + pglob->gl_pathv[i] = new; +@@ -1276,32 +1306,12 @@ libc_hidden_def (glob) + #endif + + +-#if !defined _LIBC || !defined GLOB_ONLY_P +- +-/* Free storage allocated in PGLOB by a previous `glob' call. */ +-void +-globfree (glob_t *pglob) +-{ +- if (pglob->gl_pathv != NULL) +- { +- size_t i; +- for (i = 0; i < pglob->gl_pathc; ++i) +- free (pglob->gl_pathv[pglob->gl_offs + i]); +- free (pglob->gl_pathv); +- pglob->gl_pathv = NULL; +- } +-} +-#if defined _LIBC && !defined globfree +-libc_hidden_def (globfree) +-#endif +- +- + /* Do a collated comparison of A and B. */ + static int + collated_compare (const void *a, const void *b) + { +- const char *const s1 = *(const char *const * const) a; +- const char *const s2 = *(const char *const * const) b; ++ char *const *ps1 = a; char *s1 = *ps1; ++ char *const *ps2 = b; char *s2 = *ps2; + + if (s1 == s2) + return 0; +@@ -1322,28 +1332,24 @@ prefix_array (const char *dirname, char **array, size_t n) + { + size_t i; + size_t dirlen = strlen (dirname); +-#if defined __MSDOS__ || defined WINDOWS32 +- int sep_char = '/'; +-# define DIRSEP_CHAR sep_char +-#else +-# define DIRSEP_CHAR '/' +-#endif ++ char dirsep_char = '/'; + + if (dirlen == 1 && dirname[0] == '/') + /* DIRNAME is just "/", so normal prepending would get us "//foo". + We want "/foo" instead, so don't prepend any chars from DIRNAME. */ + dirlen = 0; ++ + #if defined __MSDOS__ || defined WINDOWS32 +- else if (dirlen > 1) ++ if (dirlen > 1) + { + if (dirname[dirlen - 1] == '/' && dirname[dirlen - 2] == ':') + /* DIRNAME is "d:/". Don't prepend the slash from DIRNAME. */ + --dirlen; + else if (dirname[dirlen - 1] == ':') + { +- /* DIRNAME is "d:". Use `:' instead of `/'. */ ++ /* DIRNAME is "d:". Use ':' instead of '/'. */ + --dirlen; +- sep_char = ':'; ++ dirsep_char = ':'; + } + } + #endif +@@ -1351,7 +1357,7 @@ prefix_array (const char *dirname, char **array, size_t n) + for (i = 0; i < n; ++i) + { + size_t eltlen = strlen (array[i]) + 1; +- char *new = (char *) malloc (dirlen + 1 + eltlen); ++ char *new = malloc (dirlen + 1 + eltlen); + if (new == NULL) + { + while (i > 0) +@@ -1361,7 +1367,7 @@ prefix_array (const char *dirname, char **array, size_t n) + + { + char *endp = mempcpy (new, dirname, dirlen); +- *endp++ = DIRSEP_CHAR; ++ *endp++ = dirsep_char; + mempcpy (endp, array[i], eltlen); + } + free (array[i]); +@@ -1371,103 +1377,57 @@ prefix_array (const char *dirname, char **array, size_t n) + return 0; + } + +- +-/* We must not compile this function twice. */ +-#if !defined _LIBC || !defined NO_GLOB_PATTERN_P +-int +-__glob_pattern_type (const char *pattern, int quote) +-{ +- const char *p; +- int ret = 0; +- +- for (p = pattern; *p != '\0'; ++p) +- switch (*p) +- { +- case '?': +- case '*': +- return 1; +- +- case '\\': +- if (quote) +- { +- if (p[1] != '\0') +- ++p; +- ret |= 2; +- } +- break; +- +- case '[': +- ret |= 4; +- break; +- +- case ']': +- if (ret & 4) +- return 1; +- break; +- } +- +- return ret; +-} +- +-/* Return nonzero if PATTERN contains any metacharacters. +- Metacharacters can be quoted with backslashes if QUOTE is nonzero. */ +-int +-__glob_pattern_p (const char *pattern, int quote) +-{ +- return __glob_pattern_type (pattern, quote) == 1; +-} +-# ifdef _LIBC +-weak_alias (__glob_pattern_p, glob_pattern_p) +-# endif +-#endif +- +-#endif /* !GLOB_ONLY_P */ +- +- + /* We put this in a separate function mainly to allow the memory + allocated with alloca to be recycled. */ +-#if !defined _LIBC || !defined GLOB_ONLY_P + static int + __attribute_noinline__ +-link_exists2_p (const char *dir, size_t dirlen, const char *fname, +- glob_t *pglob +-# ifndef _LIBC +- , int flags ++link_stat (const char *dir, size_t dirlen, const char *fname, ++ glob_t *pglob ++# if !defined _LIBC && !HAVE_FSTATAT ++ , int flags + # endif +- ) ++ ) + { + size_t fnamelen = strlen (fname); +- char *fullname = (char *) __alloca (dirlen + 1 + fnamelen + 1); ++ char *fullname = __alloca (dirlen + 1 + fnamelen + 1); + struct stat st; +-# ifndef _LIBC +- struct_stat64 st64; +-# endif + + mempcpy (mempcpy (mempcpy (fullname, dir, dirlen), "/", 1), + fname, fnamelen + 1); + +-# ifdef _LIBC +- return (*pglob->gl_stat) (fullname, &st) == 0; +-# else +- return ((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0) +- ? (*pglob->gl_stat) (fullname, &st) +- : __stat64 (fullname, &st64)) == 0); ++# if !defined _LIBC && !HAVE_FSTATAT ++ if (__builtin_expect ((flags & GLOB_ALTDIRFUNC) == 0, 1)) ++ { ++ struct_stat64 st64; ++ return __stat64 (fullname, &st64); ++ } + # endif ++ return (*pglob->gl_stat) (fullname, &st); + } +-# ifdef _LIBC +-# define link_exists_p(dfd, dirname, dirnamelen, fname, pglob, flags) \ +- (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0) \ +- ? link_exists2_p (dirname, dirnamelen, fname, pglob) \ +- : ({ struct stat64 st64; \ +- __fxstatat64 (_STAT_VER, dfd, fname, &st64, 0) == 0; })) ++ ++/* Return true if DIR/FNAME exists. */ ++static int ++link_exists_p (int dfd, const char *dir, size_t dirlen, const char *fname, ++ glob_t *pglob, int flags) ++{ ++ int status; ++# if defined _LIBC || HAVE_FSTATAT ++ if (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)) ++ status = link_stat (dir, dirlen, fname, pglob); ++ else ++ { ++ /* dfd cannot be -1 here, because dirfd never returns -1 on ++ glibc, or on hosts that have fstatat. */ ++ struct_stat64 st64; ++ status = __fxstatat64 (_STAT_VER, dfd, fname, &st64, 0); ++ } + # else +-# define link_exists_p(dfd, dirname, dirnamelen, fname, pglob, flags) \ +- link_exists2_p (dirname, dirnamelen, fname, pglob, flags) ++ status = link_stat (dir, dirlen, fname, pglob, flags); + # endif +-#endif +- ++ return status == 0 || errno == EOVERFLOW; ++} + +-/* Like `glob', but PATTERN is a final pathname component, ++/* Like 'glob', but PATTERN is a final pathname component, + and matches are searched for in DIRECTORY. + The GLOB_NOSORT bit in FLAGS is ignored. No sorting is ever done. + The GLOB_APPEND flag is assumed to be set (always appends). */ +@@ -1478,25 +1438,25 @@ glob_in_dir (const char *pattern, const char *directory, int flags, + { + size_t dirlen = strlen (directory); + void *stream = NULL; +- struct globnames +- { +- struct globnames *next; +- size_t count; +- char *name[64]; +- }; +-#define INITIAL_COUNT sizeof (init_names.name) / sizeof (init_names.name[0]) +- struct globnames init_names; +- struct globnames *names = &init_names; +- struct globnames *names_alloca = &init_names; ++# define GLOBNAMES_MEMBERS(nnames) \ ++ struct globnames *next; size_t count; char *name[nnames]; ++ struct globnames { GLOBNAMES_MEMBERS (FLEXIBLE_ARRAY_MEMBER) }; ++ struct { GLOBNAMES_MEMBERS (64) } init_names_buf; ++ struct globnames *init_names = (struct globnames *) &init_names_buf; ++ struct globnames *names = init_names; ++ struct globnames *names_alloca = init_names; + size_t nfound = 0; + size_t cur = 0; + int meta; + int save; ++ int result; + +- alloca_used += sizeof (init_names); ++ alloca_used += sizeof init_names_buf; + +- init_names.next = NULL; +- init_names.count = INITIAL_COUNT; ++ init_names->next = NULL; ++ init_names->count = ((sizeof init_names_buf ++ - offsetof (struct globnames, name)) ++ / sizeof init_names->name[0]); + + meta = __glob_pattern_type (pattern, !(flags & GLOB_NOESCAPE)); + if (meta == 0 && (flags & (GLOB_NOCHECK|GLOB_NOMAGIC))) +@@ -1516,14 +1476,16 @@ glob_in_dir (const char *pattern, const char *directory, int flags, + struct_stat64 st64; + } ust; + size_t patlen = strlen (pattern); +- int alloca_fullname = __libc_use_alloca (alloca_used +- + dirlen + 1 + patlen + 1); ++ size_t fullsize; ++ bool alloca_fullname ++ = (! size_add_wrapv (dirlen + 1, patlen + 1, &fullsize) ++ && glob_use_alloca (alloca_used, fullsize)); + char *fullname; + if (alloca_fullname) +- fullname = alloca_account (dirlen + 1 + patlen + 1, alloca_used); ++ fullname = alloca_account (fullsize, alloca_used); + else + { +- fullname = malloc (dirlen + 1 + patlen + 1); ++ fullname = malloc (fullsize); + if (fullname == NULL) + return GLOB_NOSPACE; + } +@@ -1531,9 +1493,11 @@ glob_in_dir (const char *pattern, const char *directory, int flags, + mempcpy (mempcpy (mempcpy (fullname, directory, dirlen), + "/", 1), + pattern, patlen + 1); +- if ((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0) ++ if (((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0) + ? (*pglob->gl_stat) (fullname, &ust.st) +- : __stat64 (fullname, &ust.st64)) == 0) ++ : __stat64 (fullname, &ust.st64)) ++ == 0) ++ || errno == EOVERFLOW) + /* We found this file to be existing. Now tell the rest + of the function to copy this name into the result. */ + flags |= GLOB_NOCHECK; +@@ -1555,16 +1519,10 @@ glob_in_dir (const char *pattern, const char *directory, int flags, + } + else + { +-#ifdef _LIBC + int dfd = (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0) + ? -1 : dirfd ((DIR *) stream)); +-#endif + int fnm_flags = ((!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0) +- | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0) +-#if defined _AMIGA || defined VMS +- | FNM_CASEFOLD +-#endif +- ); ++ | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0)); + flags |= GLOB_MAGCHAR; + + while (1) +@@ -1584,19 +1542,24 @@ glob_in_dir (const char *pattern, const char *directory, int flags, + } + if (d.name == NULL) + break; +- if (d.skip_entry) ++ if (readdir_result_skip_entry (d)) + continue; + + /* If we shall match only directories use the information + provided by the dirent call if possible. */ +- if ((flags & GLOB_ONLYDIR) && !readdir_result_might_be_dir (d)) +- continue; ++ if (flags & GLOB_ONLYDIR) ++ switch (readdir_result_type (d)) ++ { ++ case DT_DIR: case DT_LNK: case DT_UNKNOWN: break; ++ default: continue; ++ } + + if (fnmatch (pattern, d.name, fnm_flags) == 0) + { + /* If the file we found is a symlink we have to + make sure the target file exists. */ +- if (!readdir_result_might_be_symlink (d) ++ dirent_type type = readdir_result_type (d); ++ if (! (type == DT_LNK || type == DT_UNKNOWN) + || link_exists_p (dfd, directory, dirlen, d.name, + pglob, flags)) + { +@@ -1604,10 +1567,13 @@ glob_in_dir (const char *pattern, const char *directory, int flags, + { + struct globnames *newnames; + size_t count = names->count * 2; +- size_t size = (sizeof (struct globnames) +- + ((count - INITIAL_COUNT) +- * sizeof (char *))); +- if (__libc_use_alloca (alloca_used + size)) ++ size_t nameoff = offsetof (struct globnames, name); ++ size_t size = FLEXSIZEOF (struct globnames, name, ++ count * sizeof (char *)); ++ if ((SIZE_MAX - nameoff) / 2 / sizeof (char *) ++ < names->count) ++ goto memory_error; ++ if (glob_use_alloca (alloca_used, size)) + newnames = names_alloca + = alloca_account (size, alloca_used); + else if ((newnames = malloc (size)) +@@ -1623,6 +1589,8 @@ glob_in_dir (const char *pattern, const char *directory, int flags, + goto memory_error; + ++cur; + ++nfound; ++ if (SIZE_MAX - pglob->gl_offs <= nfound) ++ goto memory_error; + } + } + } +@@ -1633,29 +1601,27 @@ glob_in_dir (const char *pattern, const char *directory, int flags, + { + size_t len = strlen (pattern); + nfound = 1; +- names->name[cur] = (char *) malloc (len + 1); ++ names->name[cur] = malloc (len + 1); + if (names->name[cur] == NULL) + goto memory_error; + *((char *) mempcpy (names->name[cur++], pattern, len)) = '\0'; + } + +- int result = GLOB_NOMATCH; ++ result = GLOB_NOMATCH; + if (nfound != 0) + { ++ char **new_gl_pathv; + result = 0; + +- if (pglob->gl_pathc > UINTPTR_MAX - pglob->gl_offs +- || pglob->gl_pathc + pglob->gl_offs > UINTPTR_MAX - nfound +- || pglob->gl_pathc + pglob->gl_offs + nfound > UINTPTR_MAX - 1 +- || (pglob->gl_pathc + pglob->gl_offs + nfound + 1 +- > UINTPTR_MAX / sizeof (char *))) ++ if (SIZE_MAX / sizeof (char *) - pglob->gl_pathc ++ < pglob->gl_offs + nfound + 1) + goto memory_error; + +- char **new_gl_pathv; + new_gl_pathv +- = (char **) realloc (pglob->gl_pathv, +- (pglob->gl_pathc + pglob->gl_offs + nfound + 1) +- * sizeof (char *)); ++ = realloc (pglob->gl_pathv, ++ (pglob->gl_pathc + pglob->gl_offs + nfound + 1) ++ * sizeof (char *)); ++ + if (new_gl_pathv == NULL) + { + memory_error: +@@ -1671,7 +1637,7 @@ glob_in_dir (const char *pattern, const char *directory, int flags, + and this is the block assigned to OLD here. */ + if (names == NULL) + { +- assert (old == &init_names); ++ assert (old == init_names); + break; + } + cur = names->count; +@@ -1697,7 +1663,7 @@ glob_in_dir (const char *pattern, const char *directory, int flags, + and this is the block assigned to OLD here. */ + if (names == NULL) + { +- assert (old == &init_names); ++ assert (old == init_names); + break; + } + cur = names->count; +diff --git a/posix/glob64.c b/posix/glob64.c +index 6cb3d654a8..a515a1c12f 100644 +--- a/posix/glob64.c ++++ b/posix/glob64.c +@@ -43,10 +43,4 @@ glob64 (const char *pattern, int flags, + } + libc_hidden_def (glob64) + +-void +-globfree64 (glob64_t *pglob) +-{ +-} +-libc_hidden_def (globfree64) +- + stub_warning (glob64) +diff --git a/posix/glob_internal.h b/posix/glob_internal.h +new file mode 100644 +index 0000000000..12c93660b7 +--- /dev/null ++++ b/posix/glob_internal.h +@@ -0,0 +1,57 @@ ++/* Shared definition for glob and glob_pattern_p. ++ Copyright (C) 2017 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 ++ . */ ++ ++#ifndef GLOB_INTERNAL_H ++# define GLOB_INTERNAL_H ++ ++static inline int ++__glob_pattern_type (const char *pattern, int quote) ++{ ++ const char *p; ++ int ret = 0; ++ ++ for (p = pattern; *p != '\0'; ++p) ++ switch (*p) ++ { ++ case '?': ++ case '*': ++ return 1; ++ ++ case '\\': ++ if (quote) ++ { ++ if (p[1] != '\0') ++ ++p; ++ ret |= 2; ++ } ++ break; ++ ++ case '[': ++ ret |= 4; ++ break; ++ ++ case ']': ++ if (ret & 4) ++ return 1; ++ break; ++ } ++ ++ return ret; ++} ++ ++#endif /* GLOB_INTERNAL_H */ +diff --git a/posix/glob_pattern_p.c b/posix/glob_pattern_p.c +new file mode 100644 +index 0000000000..a17d337182 +--- /dev/null ++++ b/posix/glob_pattern_p.c +@@ -0,0 +1,33 @@ ++/* Return nonzero if PATTERN contains any metacharacters. ++ Copyright (C) 2017 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 ++ . */ ++ ++#ifndef _LIBC ++# include ++#endif ++ ++#include ++#include "glob_internal.h" ++ ++/* Return nonzero if PATTERN contains any metacharacters. ++ Metacharacters can be quoted with backslashes if QUOTE is nonzero. */ ++int ++__glob_pattern_p (const char *pattern, int quote) ++{ ++ return __glob_pattern_type (pattern, quote) == 1; ++} ++weak_alias (__glob_pattern_p, glob_pattern_p) +diff --git a/posix/globfree.c b/posix/globfree.c +new file mode 100644 +index 0000000000..042e29d9b0 +--- /dev/null ++++ b/posix/globfree.c +@@ -0,0 +1,41 @@ ++/* Frees the dynamically allocated storage from an earlier call to glob. ++ Copyright (C) 2017 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 ++ . */ ++ ++#ifndef _LIBC ++# include ++#endif ++ ++#include ++#include ++ ++/* Free storage allocated in PGLOB by a previous `glob' call. */ ++void ++globfree (glob_t *pglob) ++{ ++ if (pglob->gl_pathv != NULL) ++ { ++ size_t i; ++ for (i = 0; i < pglob->gl_pathc; ++i) ++ free (pglob->gl_pathv[pglob->gl_offs + i]); ++ free (pglob->gl_pathv); ++ pglob->gl_pathv = NULL; ++ } ++} ++#ifndef globfree ++libc_hidden_def (globfree) ++#endif +diff --git a/posix/globfree64.c b/posix/globfree64.c +new file mode 100644 +index 0000000000..c9f8908a4e +--- /dev/null ++++ b/posix/globfree64.c +@@ -0,0 +1,31 @@ ++/* Frees the dynamically allocated storage from an earlier call to glob. ++ Copyright (C) 2017 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 ++ . */ ++ ++#ifndef _LIBC ++# include ++#endif ++ ++#include ++#include ++ ++/* Free storage allocated in PGLOB by a previous `glob' call. */ ++void ++globfree64 (glob64_t *pglob) ++{ ++} ++libc_hidden_def (globfree64) +diff --git a/posix/globtest.sh b/posix/globtest.sh +index f9cc80b4b5..73f7ae31cc 100755 +--- a/posix/globtest.sh ++++ b/posix/globtest.sh +@@ -47,7 +47,12 @@ testout=${common_objpfx}posix/globtest-out + rm -rf $testdir $testout + mkdir $testdir + +-trap 'chmod 777 $testdir/noread; rm -fr $testdir $testout' 1 2 3 15 ++cleanup() { ++ chmod 777 $testdir/noread ++ rm -fr $testdir $testout ++} ++ ++trap cleanup 0 HUP INT QUIT TERM + + echo 1 > $testdir/file1 + echo 2 > $testdir/file2 +@@ -811,8 +816,6 @@ if test $failed -ne 0; then + fi + + if test $result -eq 0; then +- chmod 777 $testdir/noread +- rm -fr $testdir $testout + echo "All OK." > $logfile + fi + +diff --git a/posix/tst-glob-tilde.c b/posix/tst-glob-tilde.c +new file mode 100644 +index 0000000000..6886f4371f +--- /dev/null ++++ b/posix/tst-glob-tilde.c +@@ -0,0 +1,143 @@ ++/* Check for GLOB_TIDLE heap allocation issues (bugs 22320, 22325, 22332). ++ Copyright (C) 2017 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Flag which indicates whether to pass the GLOB_ONLYDIR flag. */ ++static int do_onlydir; ++ ++/* Flag which indicates whether to pass the GLOB_NOCHECK flag. */ ++static int do_nocheck; ++ ++/* Flag which indicates whether to pass the GLOB_MARK flag. */ ++static int do_mark; ++ ++/* Flag which indicates whether to pass the GLOB_NOESCAPE flag. */ ++static int do_noescape; ++ ++static void ++one_test (const char *prefix, const char *middle, const char *suffix) ++{ ++ char *pattern = xasprintf ("%s%s%s", prefix, middle, suffix); ++ int flags = GLOB_TILDE; ++ if (do_onlydir) ++ flags |= GLOB_ONLYDIR; ++ if (do_nocheck) ++ flags |= GLOB_NOCHECK; ++ if (do_mark) ++ flags |= GLOB_MARK; ++ if (do_noescape) ++ flags |= GLOB_NOESCAPE; ++ glob_t gl; ++ /* This glob call might result in crashes or memory leaks. */ ++ if (glob (pattern, flags, NULL, &gl) == 0) ++ globfree (&gl); ++ free (pattern); ++} ++ ++enum ++ { ++ /* The largest base being tested. */ ++ largest_base_size = 500000, ++ ++ /* The actual size is the base size plus a variable whose absolute ++ value is not greater than this. This helps malloc to trigger ++ overflows. */ ++ max_size_skew = 16, ++ ++ /* The maximum string length supported by repeating_string ++ below. */ ++ repeat_size = largest_base_size + max_size_skew, ++ }; ++ ++/* Used to construct strings which repeat a single character 'x'. */ ++static char *repeat; ++ ++/* Return a string of SIZE characters. */ ++const char * ++repeating_string (int size) ++{ ++ TEST_VERIFY (size >= 0); ++ TEST_VERIFY (size <= repeat_size); ++ const char *repeated_shifted = repeat + repeat_size - size; ++ TEST_VERIFY (strlen (repeated_shifted) == size); ++ return repeated_shifted; ++} ++ ++static int ++do_test (void) ++{ ++ /* Avoid network-based NSS modules and initialize nss_files with a ++ dummy lookup. This has to come before mtrace because NSS does ++ not free all memory. */ ++ __nss_configure_lookup ("passwd", "files"); ++ (void) getpwnam ("root"); ++ ++ mtrace (); ++ ++ repeat = xmalloc (repeat_size + 1); ++ memset (repeat, 'x', repeat_size); ++ repeat[repeat_size] = '\0'; ++ ++ /* These numbers control the size of the user name. The values ++ cover the minimum (0), a typical size (8), a large ++ stack-allocated size (100000), and a somewhat large ++ heap-allocated size (largest_base_size). */ ++ static const int base_sizes[] = { 0, 8, 100, 100000, largest_base_size, -1 }; ++ ++ for (do_onlydir = 0; do_onlydir < 2; ++do_onlydir) ++ for (do_nocheck = 0; do_nocheck < 2; ++do_nocheck) ++ for (do_mark = 0; do_mark < 2; ++do_mark) ++ for (do_noescape = 0; do_noescape < 2; ++do_noescape) ++ for (int base_idx = 0; base_sizes[base_idx] >= 0; ++base_idx) ++ { ++ for (int size_skew = -max_size_skew; size_skew <= max_size_skew; ++ ++size_skew) ++ { ++ int size = base_sizes[base_idx] + size_skew; ++ if (size < 0) ++ continue; ++ ++ const char *user_name = repeating_string (size); ++ one_test ("~", user_name, "/a/b"); ++ one_test ("~", user_name, "x\\x\\x////x\\a"); ++ } ++ ++ const char *user_name = repeating_string (base_sizes[base_idx]); ++ one_test ("~", user_name, ""); ++ one_test ("~", user_name, "/"); ++ one_test ("~", user_name, "/a"); ++ one_test ("~", user_name, "/*/*"); ++ one_test ("~", user_name, "\\/"); ++ one_test ("/~", user_name, ""); ++ one_test ("*/~", user_name, "/a/b"); ++ } ++ ++ free (repeat); ++ ++ return 0; ++} ++ ++#include +diff --git a/resolv/Makefile b/resolv/Makefile +index fdc37edff1..01086d569f 100644 +--- a/resolv/Makefile ++++ b/resolv/Makefile +@@ -46,6 +46,7 @@ tests += \ + tst-res_hconf_reorder \ + tst-res_use_inet6 \ + tst-resolv-basic \ ++ tst-resolv-edns \ + tst-resolv-network \ + tst-resolv-search \ + +@@ -124,6 +125,7 @@ $(objpfx)tst-bug18665-tcp: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-bug18665: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-res_use_inet6: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-basic: $(objpfx)libresolv.so $(shared-thread-library) ++$(objpfx)tst-resolv-edns: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-network: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-qtypes: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-search: $(objpfx)libresolv.so $(shared-thread-library) +diff --git a/resolv/res_mkquery.c b/resolv/res_mkquery.c +index d80b5318e5..5a0bb1044b 100644 +--- a/resolv/res_mkquery.c ++++ b/resolv/res_mkquery.c +@@ -69,7 +69,7 @@ + #include + #include + #include +-#include ++#include + #include + #include + #include +@@ -243,7 +243,30 @@ __res_nopt(res_state statp, + *cp++ = 0; /* "." */ + + NS_PUT16(T_OPT, cp); /* TYPE */ +- NS_PUT16(MIN(anslen, 0xffff), cp); /* CLASS = UDP payload size */ ++ ++ /* Lowering the advertised buffer size based on the actual ++ answer buffer size is desirable because the server will ++ minimize the reply to fit into the UDP packet (and A ++ non-minimal response might not fit the buffer). ++ ++ The RESOLV_EDNS_BUFFER_SIZE limit could still result in TCP ++ fallback and a non-minimal response which has to be ++ hard-truncated in the stub resolver, but this is price to ++ pay for avoiding fragmentation. (This issue does not ++ affect the nss_dns functions because they use the stub ++ resolver in such a way that it allocates a properly sized ++ response buffer.) */ ++ { ++ uint16_t buffer_size; ++ if (anslen < 512) ++ buffer_size = 512; ++ else if (anslen > RESOLV_EDNS_BUFFER_SIZE) ++ buffer_size = RESOLV_EDNS_BUFFER_SIZE; ++ else ++ buffer_size = anslen; ++ NS_PUT16 (buffer_size, cp); ++ } ++ + *cp++ = NOERROR; /* extended RCODE */ + *cp++ = 0; /* EDNS version */ + +@@ -261,4 +284,3 @@ __res_nopt(res_state statp, + + return cp - buf; + } +-libresolv_hidden_def (__res_nopt) +diff --git a/resolv/res_query.c b/resolv/res_query.c +index 07dc6f6583..57156d01ec 100644 +--- a/resolv/res_query.c ++++ b/resolv/res_query.c +@@ -77,6 +77,7 @@ + #include + #include + #include ++#include + + /* Options. Leave them on. */ + /* #undef DEBUG */ +@@ -146,7 +147,10 @@ __libc_res_nquery(res_state statp, + if ((oflags & RES_F_EDNS0ERR) == 0 + && (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0) + { +- n = __res_nopt(statp, n, query1, bufsize, anslen / 2); ++ /* Use RESOLV_EDNS_BUFFER_SIZE because the receive ++ buffer can be reallocated. */ ++ n = __res_nopt (statp, n, query1, bufsize, ++ RESOLV_EDNS_BUFFER_SIZE); + if (n < 0) + goto unspec_nomem; + } +@@ -167,8 +171,10 @@ __libc_res_nquery(res_state statp, + if (n > 0 + && (oflags & RES_F_EDNS0ERR) == 0 + && (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0) +- n = __res_nopt(statp, n, query2, bufsize - nused - n, +- anslen / 2); ++ /* Use RESOLV_EDNS_BUFFER_SIZE because the receive ++ buffer can be reallocated. */ ++ n = __res_nopt (statp, n, query2, bufsize, ++ RESOLV_EDNS_BUFFER_SIZE); + nquery2 = n; + } + +@@ -182,7 +188,16 @@ __libc_res_nquery(res_state statp, + if (n > 0 + && (oflags & RES_F_EDNS0ERR) == 0 + && (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0) +- n = __res_nopt(statp, n, query1, bufsize, anslen); ++ { ++ /* Use RESOLV_EDNS_BUFFER_SIZE if the receive buffer ++ can be reallocated. */ ++ size_t advertise; ++ if (answerp == NULL) ++ advertise = anslen; ++ else ++ advertise = RESOLV_EDNS_BUFFER_SIZE; ++ n = __res_nopt (statp, n, query1, bufsize, advertise); ++ } + + nquery1 = n; + } +diff --git a/resolv/resolv-internal.h b/resolv/resolv-internal.h +index 99fc17c609..76fbe2f1a6 100644 +--- a/resolv/resolv-internal.h ++++ b/resolv/resolv-internal.h +@@ -32,4 +32,22 @@ res_use_inet6 (void) + return _res.options & DEPRECATED_RES_USE_INET6; + } + ++enum ++ { ++ /* The advertized EDNS buffer size. The value 1200 is derived ++ from the IPv6 minimum MTU (1280 bytes) minus some arbitrary ++ space for tunneling overhead. If the DNS server does not react ++ to ICMP Fragmentation Needed But DF Set messages, this should ++ avoid all UDP fragments on current networks. Avoiding UDP ++ fragments is desirable because it prevents fragmentation-based ++ spoofing attacks because the randomness in a DNS packet is ++ concentrated in the first fragment (with the headers) and does ++ not protect subsequent fragments. */ ++ RESOLV_EDNS_BUFFER_SIZE = 1200, ++ }; ++ ++/* Add an OPT record to a DNS query. */ ++int __res_nopt (res_state, int n0, unsigned char *buf, int buflen, ++ int anslen) attribute_hidden; ++ + #endif /* _RESOLV_INTERNAL_H */ +diff --git a/resolv/tst-resolv-edns.c b/resolv/tst-resolv-edns.c +new file mode 100644 +index 0000000000..f17dbc3450 +--- /dev/null ++++ b/resolv/tst-resolv-edns.c +@@ -0,0 +1,501 @@ ++/* Test EDNS handling in the stub resolver. ++ Copyright (C) 2016-2017 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Data produced by a test query. */ ++struct response_data ++{ ++ char *qname; ++ uint16_t qtype; ++ struct resolv_edns_info edns; ++}; ++ ++/* Global array used by put_response and get_response to record ++ response data. The test DNS server returns the index of the array ++ element which contains the actual response data. This enables the ++ test case to return arbitrary amounts of data with the limited ++ number of bits which fit into an IP addres. ++ ++ The volatile specifier is needed because the test case accesses ++ these variables from a callback function called from a function ++ which is marked as __THROW (i.e., a leaf function which actually is ++ not). */ ++static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; ++static struct response_data ** volatile response_data_array; ++volatile static size_t response_data_count; ++ ++/* Extract information from the query, store it in a struct ++ response_data object, and return its index in the ++ response_data_array. */ ++static unsigned int ++put_response (const struct resolv_response_context *ctx, ++ const char *qname, uint16_t qtype) ++{ ++ xpthread_mutex_lock (&mutex); ++ ++response_data_count; ++ /* We only can represent 2**24 indexes in 10.0.0.0/8. */ ++ TEST_VERIFY (response_data_count < (1 << 24)); ++ response_data_array = xrealloc ++ (response_data_array, sizeof (*response_data_array) * response_data_count); ++ unsigned int index = response_data_count - 1; ++ struct response_data *data = xmalloc (sizeof (*data)); ++ *data = (struct response_data) ++ { ++ .qname = xstrdup (qname), ++ .qtype = qtype, ++ .edns = ctx->edns, ++ }; ++ response_data_array[index] = data; ++ xpthread_mutex_unlock (&mutex); ++ return index; ++} ++ ++/* Verify the index into the response_data array and return the data ++ at it. */ ++static struct response_data * ++get_response (unsigned int index) ++{ ++ xpthread_mutex_lock (&mutex); ++ TEST_VERIFY_EXIT (index < response_data_count); ++ struct response_data *result = response_data_array[index]; ++ xpthread_mutex_unlock (&mutex); ++ return result; ++} ++ ++/* Deallocate all response data. */ ++static void ++free_response_data (void) ++{ ++ xpthread_mutex_lock (&mutex); ++ size_t count = response_data_count; ++ struct response_data **array = response_data_array; ++ for (unsigned int i = 0; i < count; ++i) ++ { ++ struct response_data *data = array[i]; ++ free (data->qname); ++ free (data); ++ } ++ free (array); ++ response_data_array = NULL; ++ response_data_count = 0; ++ xpthread_mutex_unlock (&mutex); ++} ++ ++#define EDNS_PROBE_EXAMPLE "edns-probe.example" ++ ++static void ++response (const struct resolv_response_context *ctx, ++ struct resolv_response_builder *b, ++ const char *qname, uint16_t qclass, uint16_t qtype) ++{ ++ TEST_VERIFY_EXIT (qname != NULL); ++ ++ /* The "tcp." prefix can be used to request TCP fallback. */ ++ const char *qname_compare = qname; ++ bool force_tcp; ++ if (strncmp ("tcp.", qname_compare, strlen ("tcp.")) == 0) ++ { ++ force_tcp = true; ++ qname_compare += strlen ("tcp."); ++ } ++ else ++ force_tcp = false; ++ ++ enum {edns_probe} requested_qname; ++ if (strcmp (qname_compare, EDNS_PROBE_EXAMPLE) == 0) ++ requested_qname = edns_probe; ++ else ++ { ++ support_record_failure (); ++ printf ("error: unexpected QNAME: %s\n", qname); ++ return; ++ } ++ TEST_VERIFY_EXIT (qclass == C_IN); ++ struct resolv_response_flags flags = {.tc = force_tcp && !ctx->tcp}; ++ resolv_response_init (b, flags); ++ resolv_response_add_question (b, qname, qclass, qtype); ++ if (flags.tc) ++ return; ++ ++ if (test_verbose) ++ printf ("info: edns=%d payload_size=%d\n", ++ ctx->edns.active, ctx->edns.payload_size); ++ ++ /* Encode the response_data object in multiple address records. ++ Each record carries two bytes of payload data, and an index. */ ++ resolv_response_section (b, ns_s_an); ++ switch (requested_qname) ++ { ++ case edns_probe: ++ { ++ unsigned int index = put_response (ctx, qname, qtype); ++ switch (qtype) ++ { ++ case T_A: ++ { ++ uint32_t addr = htonl (0x0a000000 | index); ++ resolv_response_open_record (b, qname, qclass, qtype, 0); ++ resolv_response_add_data (b, &addr, sizeof (addr)); ++ resolv_response_close_record (b); ++ } ++ break; ++ case T_AAAA: ++ { ++ char addr[16] ++ = {0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ index >> 16, index >> 8, index}; ++ resolv_response_open_record (b, qname, qclass, qtype, 0); ++ resolv_response_add_data (b, &addr, sizeof (addr)); ++ resolv_response_close_record (b); ++ } ++ } ++ } ++ break; ++ } ++} ++ ++/* Update *DATA with data from ADDRESS of SIZE. Set the corresponding ++ flag in SHADOW for each byte written. */ ++static struct response_data * ++decode_address (const void *address, size_t size) ++{ ++ switch (size) ++ { ++ case 4: ++ TEST_VERIFY (memcmp (address, "\x0a", 1) == 0); ++ break; ++ case 16: ++ TEST_VERIFY (memcmp (address, "\x20\x01\x0d\xb8", 4) == 0); ++ break; ++ default: ++ FAIL_EXIT1 ("unexpected address size %zu", size); ++ } ++ const unsigned char *addr = address; ++ unsigned int index = addr[size - 3] * 256 * 256 ++ + addr[size - 2] * 256 ++ + addr[size - 1]; ++ return get_response (index); ++} ++ ++static struct response_data * ++decode_hostent (struct hostent *e) ++{ ++ TEST_VERIFY_EXIT (e != NULL); ++ TEST_VERIFY_EXIT (e->h_addr_list[0] != NULL); ++ TEST_VERIFY (e->h_addr_list[1] == NULL); ++ return decode_address (e->h_addr_list[0], e->h_length); ++} ++ ++static struct response_data * ++decode_addrinfo (struct addrinfo *ai, int family) ++{ ++ struct response_data *data = NULL; ++ while (ai != NULL) ++ { ++ if (ai->ai_family == family) ++ { ++ struct response_data *new_data; ++ switch (family) ++ { ++ case AF_INET: ++ { ++ struct sockaddr_in *pin = (struct sockaddr_in *) ai->ai_addr; ++ new_data = decode_address (&pin->sin_addr.s_addr, 4); ++ } ++ break; ++ case AF_INET6: ++ { ++ struct sockaddr_in6 *pin = (struct sockaddr_in6 *) ai->ai_addr; ++ new_data = decode_address (&pin->sin6_addr.s6_addr, 16); ++ } ++ break; ++ default: ++ FAIL_EXIT1 ("invalid address family %d", ai->ai_family); ++ } ++ if (data == NULL) ++ data = new_data; ++ else ++ /* Check pointer equality because this should be the same ++ response (same index). */ ++ TEST_VERIFY (data == new_data); ++ } ++ ai = ai->ai_next; ++ } ++ TEST_VERIFY_EXIT (data != NULL); ++ return data; ++} ++ ++/* Updated by the main test loop in accordance with what is set in ++ _res.options. */ ++static bool use_edns; ++static bool use_dnssec; ++ ++/* Verify the decoded response data against the flags above. */ ++static void ++verify_response_data_payload (struct response_data *data, ++ size_t expected_payload) ++{ ++ bool edns = use_edns || use_dnssec; ++ TEST_VERIFY (data->edns.active == edns); ++ if (!edns) ++ expected_payload = 0; ++ if (data->edns.payload_size != expected_payload) ++ { ++ support_record_failure (); ++ printf ("error: unexpected payload size %d (edns=%d)\n", ++ (int) data->edns.payload_size, edns); ++ } ++ uint16_t expected_flags = 0; ++ if (use_dnssec) ++ expected_flags |= 0x8000; /* DO flag. */ ++ if (data->edns.flags != expected_flags) ++ { ++ support_record_failure (); ++ printf ("error: unexpected EDNS flags 0x%04x (edns=%d)\n", ++ (int) data->edns.flags, edns); ++ } ++} ++ ++/* Same as verify_response_data_payload, but use the default ++ payload. */ ++static void ++verify_response_data (struct response_data *data) ++{ ++ verify_response_data_payload (data, 1200); ++} ++ ++static void ++check_hostent (struct hostent *e) ++{ ++ TEST_VERIFY_EXIT (e != NULL); ++ verify_response_data (decode_hostent (e)); ++} ++ ++static void ++do_ai (int family) ++{ ++ struct addrinfo hints = { .ai_family = family }; ++ struct addrinfo *ai; ++ int ret = getaddrinfo (EDNS_PROBE_EXAMPLE, "80", &hints, &ai); ++ TEST_VERIFY_EXIT (ret == 0); ++ switch (family) ++ { ++ case AF_INET: ++ case AF_INET6: ++ verify_response_data (decode_addrinfo (ai, family)); ++ break; ++ case AF_UNSPEC: ++ verify_response_data (decode_addrinfo (ai, AF_INET)); ++ verify_response_data (decode_addrinfo (ai, AF_INET6)); ++ break; ++ default: ++ FAIL_EXIT1 ("invalid address family %d", family); ++ } ++ freeaddrinfo (ai); ++} ++ ++enum res_op ++{ ++ res_op_search, ++ res_op_query, ++ res_op_querydomain, ++ res_op_nsearch, ++ res_op_nquery, ++ res_op_nquerydomain, ++ ++ res_op_last = res_op_nquerydomain, ++}; ++ ++static const char * ++res_op_string (enum res_op op) ++{ ++ switch (op) ++ { ++ case res_op_search: ++ return "res_search"; ++ case res_op_query: ++ return "res_query"; ++ case res_op_querydomain: ++ return "res_querydomain"; ++ case res_op_nsearch: ++ return "res_nsearch"; ++ case res_op_nquery: ++ return "res_nquery"; ++ case res_op_nquerydomain: ++ return "res_nquerydomain"; ++ } ++ FAIL_EXIT1 ("invalid res_op value %d", (int) op); ++} ++ ++/* Call libresolv function OP to look up PROBE_NAME, with an answer ++ buffer of SIZE bytes. Check that the advertised UDP buffer size is ++ in fact EXPECTED_BUFFER_SIZE. */ ++static void ++do_res_search (const char *probe_name, enum res_op op, size_t size, ++ size_t expected_buffer_size) ++{ ++ if (test_verbose) ++ printf ("info: testing %s with buffer size %zu\n", ++ res_op_string (op), size); ++ unsigned char *buffer = xmalloc (size); ++ int ret = -1; ++ switch (op) ++ { ++ case res_op_search: ++ ret = res_search (probe_name, C_IN, T_A, buffer, size); ++ break; ++ case res_op_query: ++ ret = res_query (probe_name, C_IN, T_A, buffer, size); ++ break; ++ case res_op_nsearch: ++ ret = res_nsearch (&_res, probe_name, C_IN, T_A, buffer, size); ++ break; ++ case res_op_nquery: ++ ret = res_nquery (&_res, probe_name, C_IN, T_A, buffer, size); ++ break; ++ case res_op_querydomain: ++ case res_op_nquerydomain: ++ { ++ char *example_stripped = xstrdup (probe_name); ++ char *dot_example = strstr (example_stripped, ".example"); ++ if (dot_example != NULL && strcmp (dot_example, ".example") == 0) ++ { ++ /* Truncate the domain name. */ ++ *dot_example = '\0'; ++ if (op == res_op_querydomain) ++ ret = res_querydomain ++ (example_stripped, "example", C_IN, T_A, buffer, size); ++ else ++ ret = res_nquerydomain ++ (&_res, example_stripped, "example", C_IN, T_A, buffer, size); ++ } ++ else ++ FAIL_EXIT1 ("invalid probe name: %s", probe_name); ++ free (example_stripped); ++ } ++ break; ++ } ++ TEST_VERIFY_EXIT (ret > 12); ++ unsigned char *end = buffer + ret; ++ ++ HEADER *hd = (HEADER *) buffer; ++ TEST_VERIFY (ntohs (hd->qdcount) == 1); ++ TEST_VERIFY (ntohs (hd->ancount) == 1); ++ /* Skip over the header. */ ++ unsigned char *p = buffer + sizeof (*hd); ++ /* Skip over the question. */ ++ ret = dn_skipname (p, end); ++ TEST_VERIFY_EXIT (ret > 0); ++ p += ret; ++ TEST_VERIFY_EXIT (end - p >= 4); ++ p += 4; ++ /* Skip over the RNAME and the RR header, but stop at the RDATA ++ length. */ ++ ret = dn_skipname (p, end); ++ TEST_VERIFY_EXIT (ret > 0); ++ p += ret; ++ TEST_VERIFY_EXIT (end - p >= 2 + 2 + 4 + 2 + 4); ++ p += 2 + 2 + 4; ++ /* The IP address should be 4 bytes long. */ ++ TEST_VERIFY_EXIT (p[0] == 0); ++ TEST_VERIFY_EXIT (p[1] == 4); ++ /* Extract the address information. */ ++ p += 2; ++ struct response_data *data = decode_address (p, 4); ++ ++ verify_response_data_payload (data, expected_buffer_size); ++ ++ free (buffer); ++} ++ ++static void ++run_test (const char *probe_name) ++{ ++ if (test_verbose) ++ printf ("\ninfo: * use_edns=%d use_dnssec=%d\n", ++ use_edns, use_dnssec); ++ check_hostent (gethostbyname (probe_name)); ++ check_hostent (gethostbyname2 (probe_name, AF_INET)); ++ check_hostent (gethostbyname2 (probe_name, AF_INET6)); ++ do_ai (AF_UNSPEC); ++ do_ai (AF_INET); ++ do_ai (AF_INET6); ++ ++ for (int op = 0; op <= res_op_last; ++op) ++ { ++ do_res_search (probe_name, op, 301, 512); ++ do_res_search (probe_name, op, 511, 512); ++ do_res_search (probe_name, op, 512, 512); ++ do_res_search (probe_name, op, 513, 513); ++ do_res_search (probe_name, op, 657, 657); ++ do_res_search (probe_name, op, 1199, 1199); ++ do_res_search (probe_name, op, 1200, 1200); ++ do_res_search (probe_name, op, 1201, 1200); ++ do_res_search (probe_name, op, 65535, 1200); ++ } ++} ++ ++static int ++do_test (void) ++{ ++ for (int do_edns = 0; do_edns < 2; ++do_edns) ++ for (int do_dnssec = 0; do_dnssec < 2; ++do_dnssec) ++ for (int do_tcp = 0; do_tcp < 2; ++do_tcp) ++ { ++ struct resolv_test *aux = resolv_test_start ++ ((struct resolv_redirect_config) ++ { ++ .response_callback = response, ++ }); ++ ++ use_edns = do_edns; ++ if (do_edns) ++ _res.options |= RES_USE_EDNS0; ++ use_dnssec = do_dnssec; ++ if (do_dnssec) ++ _res.options |= RES_USE_DNSSEC; ++ ++ char *probe_name = xstrdup (EDNS_PROBE_EXAMPLE); ++ if (do_tcp) ++ { ++ char *n = xasprintf ("tcp.%s", probe_name); ++ free (probe_name); ++ probe_name = n; ++ } ++ ++ run_test (probe_name); ++ ++ free (probe_name); ++ resolv_test_end (aux); ++ } ++ ++ free_response_data (); ++ return 0; ++} ++ ++#include +diff --git a/resolv/tst-resolv-qtypes.c b/resolv/tst-resolv-qtypes.c +index dcb39e505e..da3325f80c 100644 +--- a/resolv/tst-resolv-qtypes.c ++++ b/resolv/tst-resolv-qtypes.c +@@ -50,7 +50,7 @@ response (const struct resolv_response_context *ctx, + resolv_response_close_record (b); + } + +-static const const char *domain = "www.example.com"; ++static const char domain[] = "www.example.com"; + + static int + wrap_res_query (int type, unsigned char *answer, int answer_length) +diff --git a/scripts/backport-support.sh b/scripts/backport-support.sh +new file mode 100644 +index 0000000000..2ece7ce575 +--- /dev/null ++++ b/scripts/backport-support.sh +@@ -0,0 +1,110 @@ ++#!/bin/bash ++# Create a patch which backports the support/ subdirectory. ++# Copyright (C) 2017 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 ++# . ++ ++# This script does not backport the Makefile tweaks outside the ++# support/ directory (which need to be backported separately), or the ++# changes to test-skeleton.c (which should not be backported). ++ ++set -e ++ ++export LC_ALL=C ++export GIT_CONFIG=/dev/null ++export GTT_CONFIG_NOSYSTEM=0 ++export GIT_PAGER= ++ ++usage () { ++ cat >&2 <&2 ++ echo "# rm -rf $patch_targets" >&2 ++} ++ ++command_commit () { ++ git status --porcelain | while read line ; do ++ echo "error: working copy is not clean, cannot commit" >&2 ++ exit 1 ++ done ++ for path in $patch_targets; do ++ echo "# Processing $path" >&2 ++ case "$path" in ++ [a-zA-Z0-9]*/) ++ # Directory. ++ git rm --cached --ignore-unmatch -r "$path" ++ rm -rf "$path" ++ git read-tree --prefix="$path" "$latest_commit":"$path" ++ git checkout "$path" ++ ;; ++ *) ++ # File. ++ git show "$latest_commit":"$path" > "$path" ++ git add "$path" ++ esac ++ done ++ git commit -m "Synchronize support/ infrastructure with $branch_name ++ ++This commit updates the support/ subdirectory to ++commit $latest_commit ++on the $branch_name branch. ++" ++} ++ ++command_$command +diff --git a/stdlib/getentropy.c b/stdlib/getentropy.c +index a71d4cd8f5..a88bbf8de3 100644 +--- a/stdlib/getentropy.c ++++ b/stdlib/getentropy.c +@@ -21,7 +21,7 @@ + + /* Write LENGTH bytes of randomness starting at BUFFER. Return 0 on + success and -1 on failure. */ +-ssize_t ++int + getentropy (void *buffer, size_t length) + { + __set_errno (ENOSYS); +diff --git a/string/stratcliff.c b/string/stratcliff.c +index e672644888..2cd8686082 100644 +--- a/string/stratcliff.c ++++ b/string/stratcliff.c +@@ -58,8 +58,8 @@ + static int + do_test (void) + { +- int size = sysconf (_SC_PAGESIZE); +- int nchars = size / sizeof (CHAR); ++ size_t size = sysconf (_SC_PAGESIZE); ++ size_t nchars = size / sizeof (CHAR); + CHAR *adr; + CHAR *dest; + int result = 0; +@@ -80,7 +80,17 @@ do_test (void) + } + else + { +- int inner, middle, outer; ++ size_t inner, middle, outer, nchars64, max128; ++ ++ if (nchars > 64) ++ nchars64 = nchars - 64; ++ else ++ nchars64 = 0; ++ ++ if (nchars > 128) ++ max128 = nchars - 128; ++ else ++ max128 = 0; + + mprotect (adr, size, PROT_NONE); + mprotect (adr + 2 * nchars, size, PROT_NONE); +@@ -93,59 +103,65 @@ do_test (void) + MEMSET (adr, L('T'), nchars); + + /* strlen/wcslen test */ +- for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) ++ for (outer = nchars - 1; outer >= max128; --outer) + { +- for (inner = MAX (outer, nchars - 64); inner < nchars; ++inner) ++ for (inner = MAX (outer, nchars64); inner < nchars; ++inner) + { + adr[inner] = L('\0'); + + if (STRLEN (&adr[outer]) != (size_t) (inner - outer)) + { +- printf ("%s flunked for outer = %d, inner = %d\n", ++ printf ("%s flunked for outer = %zu, inner = %zu\n", + STRINGIFY (STRLEN), outer, inner); + result = 1; + } + + adr[inner] = L('T'); + } ++ if (outer == 0) ++ break; + } + + /* strnlen/wcsnlen test */ +- for (outer = nchars; outer >= MAX (0, nchars - 128); --outer) ++ for (outer = nchars; outer >= max128; --outer) + { +- for (inner = MAX (outer, nchars - 64); inner < nchars; ++inner) ++ for (inner = MAX (outer, nchars64); inner < nchars; ++inner) + { + adr[inner] = L('\0'); + + if (STRNLEN (&adr[outer], inner - outer + 1) + != (size_t) (inner - outer)) + { +- printf ("%s flunked for outer = %d, inner = %d\n", ++ printf ("%s flunked for outer = %zu, inner = %zu\n", + STRINGIFY (STRNLEN), outer, inner); + result = 1; + } + + adr[inner] = L('T'); + } ++ if (outer == 0) ++ break; + } +- for (outer = nchars; outer >= MAX (0, nchars - 128); --outer) ++ for (outer = nchars; outer >= max128; --outer) + { +- for (inner = MAX (outer, nchars - 64); inner <= nchars; ++inner) ++ for (inner = MAX (outer, nchars64); inner <= nchars; ++inner) + { + if (STRNLEN (&adr[outer], inner - outer) + != (size_t) (inner - outer)) + { +- printf ("%s flunked bounded for outer = %d, inner = %d\n", ++ printf ("%s flunked bounded for outer = %zu, inner = %zu\n", + STRINGIFY (STRNLEN), outer, inner); + result = 1; + } + } ++ if (outer == 0) ++ break; + } + + /* strchr/wcschr test */ +- for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) ++ for (outer = nchars - 1; outer >= max128; --outer) + { +- for (middle = MAX (outer, nchars - 64); middle < nchars; ++middle) ++ for (middle = MAX (outer, nchars64); middle < nchars; ++middle) + { + for (inner = middle; inner < nchars; ++inner) + { +@@ -158,8 +174,8 @@ do_test (void) + || (inner != middle + && (cp - &adr[outer]) != middle - outer)) + { +- printf ("%s flunked for outer = %d, middle = %d, " +- "inner = %d\n", ++ printf ("%s flunked for outer = %zu, middle = %zu, " ++ "inner = %zu\n", + STRINGIFY (STRCHR), outer, middle, inner); + result = 1; + } +@@ -168,6 +184,8 @@ do_test (void) + adr[middle] = L('T'); + } + } ++ if (outer == 0) ++ break; + } + + /* Special test. */ +@@ -180,9 +198,9 @@ do_test (void) + } + + /* strrchr/wcsrchr test */ +- for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) ++ for (outer = nchars - 1; outer >= max128; --outer) + { +- for (middle = MAX (outer, nchars - 64); middle < nchars; ++middle) ++ for (middle = MAX (outer, nchars64); middle < nchars; ++middle) + { + for (inner = middle; inner < nchars; ++inner) + { +@@ -195,8 +213,8 @@ do_test (void) + || (inner != middle + && (cp - &adr[outer]) != middle - outer)) + { +- printf ("%s flunked for outer = %d, middle = %d, " +- "inner = %d\n", ++ printf ("%s flunked for outer = %zu, middle = %zu, " ++ "inner = %zu\n", + STRINGIFY (STRRCHR), outer, middle, inner); + result = 1; + } +@@ -205,12 +223,14 @@ do_test (void) + adr[middle] = L('T'); + } + } ++ if (outer == 0) ++ break; + } + + /* memchr test */ +- for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) ++ for (outer = nchars - 1; outer >= max128; --outer) + { +- for (middle = MAX (outer, nchars - 64); middle < nchars; ++middle) ++ for (middle = MAX (outer, nchars64); middle < nchars; ++middle) + { + adr[middle] = L('V'); + +@@ -218,32 +238,36 @@ do_test (void) + + if (cp - &adr[outer] != middle - outer) + { +- printf ("%s flunked for outer = %d, middle = %d\n", ++ printf ("%s flunked for outer = %zu, middle = %zu\n", + STRINGIFY (MEMCHR), outer, middle); + result = 1; + } + + adr[middle] = L('T'); + } ++ if (outer == 0) ++ break; + } +- for (outer = nchars; outer >= MAX (0, nchars - 128); --outer) ++ for (outer = nchars; outer >= max128; --outer) + { + CHAR *cp = MEMCHR (&adr[outer], L('V'), nchars - outer); + + if (cp != NULL) + { +- printf ("%s flunked for outer = %d\n", ++ printf ("%s flunked for outer = %zu\n", + STRINGIFY (MEMCHR), outer); + result = 1; + } ++ if (outer == 0) ++ break; + } + + /* These functions only exist for single-byte characters. */ + #ifndef WCSTEST + /* rawmemchr test */ +- for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) ++ for (outer = nchars - 1; outer >= max128; --outer) + { +- for (middle = MAX (outer, nchars - 64); middle < nchars; ++middle) ++ for (middle = MAX (outer, nchars64); middle < nchars; ++middle) + { + adr[middle] = L('V'); + +@@ -251,19 +275,21 @@ do_test (void) + + if (cp - &adr[outer] != middle - outer) + { +- printf ("%s flunked for outer = %d, middle = %d\n", ++ printf ("%s flunked for outer = %zu, middle = %zu\n", + STRINGIFY (rawmemchr), outer, middle); + result = 1; + } + + adr[middle] = L('T'); + } ++ if (outer == 0) ++ break; + } + + /* memrchr test */ +- for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) ++ for (outer = nchars - 1; outer >= max128; --outer) + { +- for (middle = MAX (outer, nchars - 64); middle < nchars; ++middle) ++ for (middle = MAX (outer, nchars64); middle < nchars; ++middle) + { + adr[middle] = L('V'); + +@@ -271,44 +297,50 @@ do_test (void) + + if (cp - &adr[outer] != middle - outer) + { +- printf ("%s flunked for outer = %d, middle = %d\n", ++ printf ("%s flunked for outer = %zu, middle = %zu\n", + STRINGIFY (memrchr), outer, middle); + result = 1; + } + + adr[middle] = L('T'); + } ++ if (outer == 0) ++ break; + } +- for (outer = nchars; outer >= MAX (0, nchars - 128); --outer) ++ for (outer = nchars; outer >= max128; --outer) + { + CHAR *cp = memrchr (&adr[outer], L('V'), nchars - outer); + + if (cp != NULL) + { +- printf ("%s flunked for outer = %d\n", ++ printf ("%s flunked for outer = %zu\n", + STRINGIFY (memrchr), outer); + result = 1; + } ++ if (outer == 0) ++ break; + } + #endif + + /* strcpy/wcscpy test */ +- for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) ++ for (outer = nchars - 1; outer >= max128; --outer) + { +- for (inner = MAX (outer, nchars - 64); inner < nchars; ++inner) ++ for (inner = MAX (outer, nchars64); inner < nchars; ++inner) + { + adr[inner] = L('\0'); + + if (STRCPY (dest, &adr[outer]) != dest + || STRLEN (dest) != (size_t) (inner - outer)) + { +- printf ("%s flunked for outer = %d, inner = %d\n", ++ printf ("%s flunked for outer = %zu, inner = %zu\n", + STRINGIFY (STRCPY), outer, inner); + result = 1; + } + + adr[inner] = L('T'); + } ++ if (outer == 0) ++ break; + } + + /* strcmp/wcscmp tests */ +@@ -322,14 +354,14 @@ do_test (void) + + if (STRCMP (adr + middle, dest + nchars - outer) <= 0) + { +- printf ("%s 1 flunked for outer = %d, middle = %d\n", ++ printf ("%s 1 flunked for outer = %zu, middle = %zu\n", + STRINGIFY (STRCMP), outer, middle); + result = 1; + } + + if (STRCMP (dest + nchars - outer, adr + middle) >= 0) + { +- printf ("%s 2 flunked for outer = %d, middle = %d\n", ++ printf ("%s 2 flunked for outer = %zu, middle = %zu\n", + STRINGIFY (STRCMP), outer, middle); + result = 1; + } +@@ -348,16 +380,16 @@ do_test (void) + { + if (STRNCMP (adr + middle, dest + nchars - outer, inner) != 0) + { +- printf ("%s 1 flunked for outer = %d, middle = %d, " +- "inner = %d\n", ++ printf ("%s 1 flunked for outer = %zu, middle = %zu, " ++ "inner = %zu\n", + STRINGIFY (STRNCMP), outer, middle, inner); + result = 1; + } + + if (STRNCMP (dest + nchars - outer, adr + middle, inner) != 0) + { +- printf ("%s 2 flunked for outer = %d, middle = %d, " +- "inner = %d\n", ++ printf ("%s 2 flunked for outer = %zu, middle = %zu, " ++ "inner = %zu\n", + STRINGIFY (STRNCMP), outer, middle, inner); + result = 1; + } +@@ -365,14 +397,14 @@ do_test (void) + + if (STRNCMP (adr + middle, dest + nchars - outer, outer) >= 0) + { +- printf ("%s 1 flunked for outer = %d, middle = %d, full\n", ++ printf ("%s 1 flunked for outer = %zu, middle = %zu, full\n", + STRINGIFY (STRNCMP), outer, middle); + result = 1; + } + + if (STRNCMP (dest + nchars - outer, adr + middle, outer) <= 0) + { +- printf ("%s 2 flunked for outer = %d, middle = %d, full\n", ++ printf ("%s 2 flunked for outer = %zu, middle = %zu, full\n", + STRINGIFY (STRNCMP), outer, middle); + result = 1; + } +@@ -380,7 +412,7 @@ do_test (void) + + /* strncpy/wcsncpy tests */ + adr[nchars - 1] = L('T'); +- for (outer = nchars; outer >= MAX (0, nchars - 128); --outer) ++ for (outer = nchars; outer >= max128; --outer) + { + size_t len; + +@@ -389,17 +421,19 @@ do_test (void) + if (STRNCPY (dest, &adr[outer], len) != dest + || MEMCMP (dest, &adr[outer], len) != 0) + { +- printf ("outer %s flunked for outer = %d, len = %Zd\n", ++ printf ("outer %s flunked for outer = %zu, len = %zu\n", + STRINGIFY (STRNCPY), outer, len); + result = 1; + } + } ++ if (outer == 0) ++ break; + } + adr[nchars - 1] = L('\0'); + +- for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) ++ for (outer = nchars - 1; outer >= max128; --outer) + { +- for (inner = MAX (outer, nchars - 64); inner < nchars; ++inner) ++ for (inner = MAX (outer, nchars64); inner < nchars; ++inner) + { + size_t len; + +@@ -413,8 +447,8 @@ do_test (void) + || (inner - outer < len + && STRLEN (dest) != (inner - outer))) + { +- printf ("%s flunked for outer = %d, inner = %d, " +- "len = %Zd\n", ++ printf ("%s flunked for outer = %zu, inner = %zu, " ++ "len = %zu\n", + STRINGIFY (STRNCPY), outer, inner, len); + result = 1; + } +@@ -424,8 +458,8 @@ do_test (void) + || (inner - outer < len + && STRLEN (dest + 1) != (inner - outer))) + { +- printf ("%s+1 flunked for outer = %d, inner = %d, " +- "len = %Zd\n", ++ printf ("%s+1 flunked for outer = %zu, inner = %zu, " ++ "len = %zu\n", + STRINGIFY (STRNCPY), outer, inner, len); + result = 1; + } +@@ -433,29 +467,33 @@ do_test (void) + + adr[inner] = L('T'); + } ++ if (outer == 0) ++ break; + } + + /* stpcpy/wcpcpy test */ +- for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) ++ for (outer = nchars - 1; outer >= max128; --outer) + { +- for (inner = MAX (outer, nchars - 64); inner < nchars; ++inner) ++ for (inner = MAX (outer, nchars64); inner < nchars; ++inner) + { + adr[inner] = L('\0'); + + if ((STPCPY (dest, &adr[outer]) - dest) != inner - outer) + { +- printf ("%s flunked for outer = %d, inner = %d\n", ++ printf ("%s flunked for outer = %zu, inner = %zu\n", + STRINGIFY (STPCPY), outer, inner); + result = 1; + } + + adr[inner] = L('T'); + } ++ if (outer == 0) ++ break; + } + + /* stpncpy/wcpncpy test */ + adr[nchars - 1] = L('T'); +- for (outer = nchars; outer >= MAX (0, nchars - 128); --outer) ++ for (outer = nchars; outer >= max128; --outer) + { + size_t len; + +@@ -464,17 +502,19 @@ do_test (void) + if (STPNCPY (dest, &adr[outer], len) != dest + len + || MEMCMP (dest, &adr[outer], len) != 0) + { +- printf ("outer %s flunked for outer = %d, len = %Zd\n", ++ printf ("outer %s flunked for outer = %zu, len = %zu\n", + STRINGIFY (STPNCPY), outer, len); + result = 1; + } + } ++ if (outer == 0) ++ break; + } + adr[nchars - 1] = L('\0'); + +- for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) ++ for (outer = nchars - 1; outer >= max128; --outer) + { +- for (middle = MAX (outer, nchars - 64); middle < nchars; ++middle) ++ for (middle = MAX (outer, nchars64); middle < nchars; ++middle) + { + adr[middle] = L('\0'); + +@@ -483,8 +523,8 @@ do_test (void) + if ((STPNCPY (dest, &adr[outer], inner) - dest) + != MIN (inner, middle - outer)) + { +- printf ("%s flunked for outer = %d, middle = %d, " +- "inner = %d\n", ++ printf ("%s flunked for outer = %zu, middle = %zu, " ++ "inner = %zu\n", + STRINGIFY (STPNCPY), outer, middle, inner); + result = 1; + } +@@ -492,66 +532,84 @@ do_test (void) + + adr[middle] = L('T'); + } ++ if (outer == 0) ++ break; + } + + /* memcpy/wmemcpy test */ +- for (outer = nchars; outer >= MAX (0, nchars - 128); --outer) +- for (inner = 0; inner < nchars - outer; ++inner) +- if (MEMCPY (dest, &adr[outer], inner) != dest) +- { +- printf ("%s flunked for outer = %d, inner = %d\n", +- STRINGIFY (MEMCPY), outer, inner); +- result = 1; +- } ++ for (outer = nchars; outer >= max128; --outer) ++ { ++ for (inner = 0; inner < nchars - outer; ++inner) ++ if (MEMCPY (dest, &adr[outer], inner) != dest) ++ { ++ printf ("%s flunked for outer = %zu, inner = %zu\n", ++ STRINGIFY (MEMCPY), outer, inner); ++ result = 1; ++ } ++ if (outer == 0) ++ break; ++ } + + /* mempcpy/wmempcpy test */ +- for (outer = nchars; outer >= MAX (0, nchars - 128); --outer) +- for (inner = 0; inner < nchars - outer; ++inner) +- if (MEMPCPY (dest, &adr[outer], inner) != dest + inner) +- { +- printf ("%s flunked for outer = %d, inner = %d\n", +- STRINGIFY (MEMPCPY), outer, inner); +- result = 1; +- } ++ for (outer = nchars; outer >= max128; --outer) ++ { ++ for (inner = 0; inner < nchars - outer; ++inner) ++ if (MEMPCPY (dest, &adr[outer], inner) != dest + inner) ++ { ++ printf ("%s flunked for outer = %zu, inner = %zu\n", ++ STRINGIFY (MEMPCPY), outer, inner); ++ result = 1; ++ } ++ if (outer == 0) ++ break; ++ } + + /* This function only exists for single-byte characters. */ + #ifndef WCSTEST + /* memccpy test */ + memset (adr, '\0', nchars); +- for (outer = nchars; outer >= MAX (0, nchars - 128); --outer) +- for (inner = 0; inner < nchars - outer; ++inner) +- if (memccpy (dest, &adr[outer], L('\1'), inner) != NULL) +- { +- printf ("memccpy flunked full copy for outer = %d, inner = %d\n", +- outer, inner); +- result = 1; +- } +- for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) +- for (middle = 0; middle < nchars - outer; ++middle) +- { +- memset (dest, L('\2'), middle + 1); +- for (inner = 0; inner < middle; ++inner) ++ for (outer = nchars; outer >= max128; --outer) ++ { ++ for (inner = 0; inner < nchars - outer; ++inner) ++ if (memccpy (dest, &adr[outer], L('\1'), inner) != NULL) + { +- adr[outer + inner] = L('\1'); +- +- if (memccpy (dest, &adr[outer], '\1', middle + 128) +- != dest + inner + 1) +- { +- printf ("\ +-memccpy flunked partial copy for outer = %d, middle = %d, inner = %d\n", +- outer, middle, inner); +- result = 1; +- } +- else if (dest[inner + 1] != L('\2')) +- { +- printf ("\ +-memccpy copied too much for outer = %d, middle = %d, inner = %d\n", +- outer, middle, inner); +- result = 1; +- } +- adr[outer + inner] = L('\0'); ++ printf ("memccpy flunked full copy for outer = %zu, inner = %zu\n", ++ outer, inner); ++ result = 1; + } +- } ++ if (outer == 0) ++ break; ++ } ++ for (outer = nchars - 1; outer >= max128; --outer) ++ { ++ for (middle = 0; middle < nchars - outer; ++middle) ++ { ++ memset (dest, L('\2'), middle + 1); ++ for (inner = 0; inner < middle; ++inner) ++ { ++ adr[outer + inner] = L('\1'); ++ ++ if (memccpy (dest, &adr[outer], '\1', middle + 128) ++ != dest + inner + 1) ++ { ++ printf ("\ ++ memccpy flunked partial copy for outer = %zu, middle = %zu, inner = %zu\n", ++ outer, middle, inner); ++ result = 1; ++ } ++ else if (dest[inner + 1] != L('\2')) ++ { ++ printf ("\ ++ memccpy copied too much for outer = %zu, middle = %zu, inner = %zu\n", ++ outer, middle, inner); ++ result = 1; ++ } ++ adr[outer + inner] = L('\0'); ++ } ++ } ++ if (outer == 0) ++ break; ++ } + #endif + } + +diff --git a/string/test-memchr.c b/string/test-memchr.c +index d62889ff8f..6431605c7e 100644 +--- a/string/test-memchr.c ++++ b/string/test-memchr.c +@@ -208,6 +208,12 @@ test_main (void) + do_test (0, i, i + 1, i + 1, 0); + } + ++ /* BZ#21182 - wrong overflow calculation for i686 implementation ++ with address near end of the page. */ ++ for (i = 2; i < 16; ++i) ++ /* page_size is in fact getpagesize() * 2. */ ++ do_test (page_size / 2 - i, i, i, 1, 0x9B); ++ + do_random_tests (); + return ret; + } +diff --git a/sunrpc/Makefile b/sunrpc/Makefile +index 0c1e6124ff..7e5d2955a0 100644 +--- a/sunrpc/Makefile ++++ b/sunrpc/Makefile +@@ -93,11 +93,12 @@ rpcgen-objs = rpc_main.o rpc_hout.o rpc_cout.o rpc_parse.o \ + extra-objs = $(rpcgen-objs) $(addprefix cross-,$(rpcgen-objs)) + others += rpcgen + +-tests = tst-xdrmem tst-xdrmem2 test-rpcent ++tests = tst-xdrmem tst-xdrmem2 test-rpcent tst-udp-error tst-udp-timeout \ ++ tst-udp-nonblocking + xtests := tst-getmyaddr + + ifeq ($(have-thread-library),yes) +-xtests += thrsvc ++xtests += thrsvc tst-udp-garbage + endif + + ifeq ($(run-built-tests),yes) +@@ -155,6 +156,7 @@ BUILD_CPPFLAGS += $(sunrpc-CPPFLAGS) + $(objpfx)tst-getmyaddr: $(common-objpfx)linkobj/libc.so + $(objpfx)tst-xdrmem: $(common-objpfx)linkobj/libc.so + $(objpfx)tst-xdrmem2: $(common-objpfx)linkobj/libc.so ++$(objpfx)tst-udp-error: $(common-objpfx)linkobj/libc.so + + $(objpfx)rpcgen: $(addprefix $(objpfx),$(rpcgen-objs)) + +@@ -234,3 +236,8 @@ $(rpcgen-tests): $(objpfx)%.out: %.x $(objpfx)rpcgen + $(built-program-cmd) -c $< -o $@; \ + $(evaluate-test) + endif ++ ++$(objpfx)tst-udp-timeout: $(common-objpfx)linkobj/libc.so ++$(objpfx)tst-udp-nonblocking: $(common-objpfx)linkobj/libc.so ++$(objpfx)tst-udp-garbage: \ ++ $(common-objpfx)linkobj/libc.so $(shared-thread-library) +diff --git a/sunrpc/clnt_udp.c b/sunrpc/clnt_udp.c +index 4d9acb1e6a..6ce16eb298 100644 +--- a/sunrpc/clnt_udp.c ++++ b/sunrpc/clnt_udp.c +@@ -55,6 +55,7 @@ + #endif + + #include ++#include + + extern u_long _create_xid (void); + +@@ -80,7 +81,9 @@ static const struct clnt_ops udp_ops = + }; + + /* +- * Private data kept per client handle ++ * Private data kept per client handle. This private struct is ++ * unfortunately part of the ABI; ypbind contains a copy of it and ++ * accesses it through CLIENT::cl_private field. + */ + struct cu_data + { +@@ -278,28 +281,38 @@ clntudp_call (/* client handle */ + int inlen; + socklen_t fromlen; + struct pollfd fd; +- int milliseconds = (cu->cu_wait.tv_sec * 1000) + +- (cu->cu_wait.tv_usec / 1000); + struct sockaddr_in from; + struct rpc_msg reply_msg; + XDR reply_xdrs; +- struct timeval time_waited; + bool_t ok; + int nrefreshes = 2; /* number of times to refresh cred */ +- struct timeval timeout; + int anyup; /* any network interface up */ + +- if (cu->cu_total.tv_usec == -1) +- { +- timeout = utimeout; /* use supplied timeout */ +- } +- else ++ struct deadline_current_time current_time = __deadline_current_time (); ++ struct deadline total_deadline; /* Determined once by overall timeout. */ ++ struct deadline response_deadline; /* Determined anew for each query. */ ++ ++ /* Choose the timeout value. For non-sending usage (xargs == NULL), ++ the total deadline does not matter, only cu->cu_wait is used ++ below. */ ++ if (xargs != NULL) + { +- timeout = cu->cu_total; /* use default timeout */ ++ struct timeval tv; ++ if (cu->cu_total.tv_usec == -1) ++ /* Use supplied timeout. */ ++ tv = utimeout; ++ else ++ /* Use default timeout. */ ++ tv = cu->cu_total; ++ if (!__is_timeval_valid_timeout (tv)) ++ return (cu->cu_error.re_status = RPC_TIMEDOUT); ++ total_deadline = __deadline_from_timeval (current_time, tv); + } + +- time_waited.tv_sec = 0; +- time_waited.tv_usec = 0; ++ /* Guard against bad timeout specification. */ ++ if (!__is_timeval_valid_timeout (cu->cu_wait)) ++ return (cu->cu_error.re_status = RPC_TIMEDOUT); ++ + call_again: + xdrs = &(cu->cu_outxdrs); + if (xargs == NULL) +@@ -325,27 +338,46 @@ send_again: + return (cu->cu_error.re_status = RPC_CANTSEND); + } + +- /* +- * Hack to provide rpc-based message passing +- */ +- if (timeout.tv_sec == 0 && timeout.tv_usec == 0) +- { +- return (cu->cu_error.re_status = RPC_TIMEDOUT); +- } ++ /* sendto may have blocked, so recompute the current time. */ ++ current_time = __deadline_current_time (); + get_reply: +- /* +- * sub-optimal code appears here because we have +- * some clock time to spare while the packets are in flight. +- * (We assume that this is actually only executed once.) +- */ ++ response_deadline = __deadline_from_timeval (current_time, cu->cu_wait); ++ + reply_msg.acpted_rply.ar_verf = _null_auth; + reply_msg.acpted_rply.ar_results.where = resultsp; + reply_msg.acpted_rply.ar_results.proc = xresults; + fd.fd = cu->cu_sock; + fd.events = POLLIN; + anyup = 0; ++ ++ /* Per-response retry loop. current_time must be up-to-date at the ++ top of the loop. */ + for (;;) + { ++ int milliseconds; ++ if (xargs != NULL) ++ { ++ if (__deadline_elapsed (current_time, total_deadline)) ++ /* Overall timeout expired. */ ++ return (cu->cu_error.re_status = RPC_TIMEDOUT); ++ milliseconds = __deadline_to_ms ++ (current_time, __deadline_first (total_deadline, ++ response_deadline)); ++ if (milliseconds == 0) ++ /* Per-query timeout expired. */ ++ goto send_again; ++ } ++ else ++ { ++ /* xatgs == NULL. Collect a response without sending a ++ query. In this mode, we need to ignore the total ++ deadline. */ ++ milliseconds = __deadline_to_ms (current_time, response_deadline); ++ if (milliseconds == 0) ++ /* Cannot send again, so bail out. */ ++ return (cu->cu_error.re_status = RPC_CANTSEND); ++ } ++ + switch (__poll (&fd, 1, milliseconds)) + { + +@@ -356,27 +388,10 @@ send_again: + if (!anyup) + return (cu->cu_error.re_status = RPC_CANTRECV); + } +- +- time_waited.tv_sec += cu->cu_wait.tv_sec; +- time_waited.tv_usec += cu->cu_wait.tv_usec; +- while (time_waited.tv_usec >= 1000000) +- { +- time_waited.tv_sec++; +- time_waited.tv_usec -= 1000000; +- } +- if ((time_waited.tv_sec < timeout.tv_sec) || +- ((time_waited.tv_sec == timeout.tv_sec) && +- (time_waited.tv_usec < timeout.tv_usec))) +- goto send_again; +- return (cu->cu_error.re_status = RPC_TIMEDOUT); +- +- /* +- * buggy in other cases because time_waited is not being +- * updated. +- */ ++ goto next_response; + case -1: + if (errno == EINTR) +- continue; ++ goto next_response; + cu->cu_error.re_errno = errno; + return (cu->cu_error.re_status = RPC_CANTRECV); + } +@@ -421,9 +436,9 @@ send_again: + cmsg = CMSG_NXTHDR (&msg, cmsg)) + if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR) + { +- free (cbuf); + e = (struct sock_extended_err *) CMSG_DATA(cmsg); + cu->cu_error.re_errno = e->ee_errno; ++ free (cbuf); + return (cu->cu_error.re_status = RPC_CANTRECV); + } + free (cbuf); +@@ -440,20 +455,22 @@ send_again: + if (inlen < 0) + { + if (errno == EWOULDBLOCK) +- continue; ++ goto next_response; + cu->cu_error.re_errno = errno; + return (cu->cu_error.re_status = RPC_CANTRECV); + } +- if (inlen < 4) +- continue; +- +- /* see if reply transaction id matches sent id. +- Don't do this if we only wait for a replay */ +- if (xargs != NULL +- && memcmp (cu->cu_inbuf, cu->cu_outbuf, sizeof (u_int32_t)) != 0) +- continue; +- /* we now assume we have the proper reply */ +- break; ++ /* Accept the response if the packet is sufficiently long and ++ the transaction ID matches the query (if available). */ ++ if (inlen >= 4 ++ && (xargs == NULL ++ || memcmp (cu->cu_inbuf, cu->cu_outbuf, ++ sizeof (u_int32_t)) == 0)) ++ break; ++ ++ next_response: ++ /* Update the current time because poll and recvmsg waited for ++ an unknown time. */ ++ current_time = __deadline_current_time (); + } + + /* +diff --git a/sunrpc/tst-udp-error.c b/sunrpc/tst-udp-error.c +new file mode 100644 +index 0000000000..1efc02f5c6 +--- /dev/null ++++ b/sunrpc/tst-udp-error.c +@@ -0,0 +1,62 @@ ++/* Check for use-after-free in clntudp_call (bug 21115). ++ Copyright (C) 2017 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ support_become_root (); ++ support_enter_network_namespace (); ++ ++ /* Obtain a likely-unused port number. */ ++ struct sockaddr_in sin = ++ { ++ .sin_family = AF_INET, ++ .sin_addr.s_addr = htonl (INADDR_LOOPBACK), ++ }; ++ { ++ int fd = xsocket (AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); ++ xbind (fd, (struct sockaddr *) &sin, sizeof (sin)); ++ socklen_t sinlen = sizeof (sin); ++ xgetsockname (fd, (struct sockaddr *) &sin, &sinlen); ++ /* Close the socket, so that we will receive an error below. */ ++ close (fd); ++ } ++ ++ int sock = RPC_ANYSOCK; ++ CLIENT *clnt = clntudp_create ++ (&sin, 1, 2, (struct timeval) { 1, 0 }, &sock); ++ TEST_VERIFY_EXIT (clnt != NULL); ++ TEST_VERIFY (clnt_call (clnt, 3, ++ (xdrproc_t) xdr_void, NULL, ++ (xdrproc_t) xdr_void, NULL, ++ ((struct timeval) { 3, 0 })) ++ == RPC_CANTRECV); ++ clnt_destroy (clnt); ++ ++ return 0; ++} ++ ++#include +diff --git a/sunrpc/tst-udp-garbage.c b/sunrpc/tst-udp-garbage.c +new file mode 100644 +index 0000000000..4abda93f08 +--- /dev/null ++++ b/sunrpc/tst-udp-garbage.c +@@ -0,0 +1,104 @@ ++/* Test that garbage packets do not affect timeout handling. ++ Copyright (C) 2017 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Descriptor for the server UDP socket. */ ++static int server_fd; ++ ++static void * ++garbage_sender_thread (void *unused) ++{ ++ while (true) ++ { ++ struct sockaddr_storage sa; ++ socklen_t salen = sizeof (sa); ++ char buf[1]; ++ if (recvfrom (server_fd, buf, sizeof (buf), 0, ++ (struct sockaddr *) &sa, &salen) < 0) ++ FAIL_EXIT1 ("recvfrom: %m"); ++ ++ /* Send garbage packets indefinitely. */ ++ buf[0] = 0; ++ while (true) ++ { ++ /* sendto can fail if the client closed the socket. */ ++ if (sendto (server_fd, buf, sizeof (buf), 0, ++ (struct sockaddr *) &sa, salen) < 0) ++ break; ++ ++ /* Wait a bit, to avoid burning too many CPU cycles in a ++ tight loop. The wait period must be much shorter than ++ the client timeouts configured below. */ ++ usleep (50 * 1000); ++ } ++ } ++} ++ ++static int ++do_test (void) ++{ ++ support_become_root (); ++ support_enter_network_namespace (); ++ ++ server_fd = xsocket (AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP); ++ struct sockaddr_in server_address = ++ { ++ .sin_family = AF_INET, ++ .sin_addr.s_addr = htonl (INADDR_LOOPBACK), ++ }; ++ xbind (server_fd, ++ (struct sockaddr *) &server_address, sizeof (server_address)); ++ { ++ socklen_t sinlen = sizeof (server_address); ++ xgetsockname (server_fd, (struct sockaddr *) &server_address, &sinlen); ++ TEST_VERIFY (sizeof (server_address) == sinlen); ++ } ++ ++ /* Garbage packet source. */ ++ xpthread_detach (xpthread_create (NULL, garbage_sender_thread, NULL)); ++ ++ /* Test client. Use an arbitrary timeout of one second, which is ++ much longer than the garbage packet interval, but still ++ reasonably short, so that the test completes quickly. */ ++ int client_fd = RPC_ANYSOCK; ++ CLIENT *clnt = clntudp_create (&server_address, ++ 1, 2, /* Arbitrary RPC endpoint numbers. */ ++ (struct timeval) { 1, 0 }, ++ &client_fd); ++ if (clnt == NULL) ++ FAIL_EXIT1 ("clntudp_create: %m"); ++ ++ TEST_VERIFY (clnt_call (clnt, 3, /* Arbitrary RPC procedure number. */ ++ (xdrproc_t) xdr_void, NULL, ++ (xdrproc_t) xdr_void, NULL, ++ ((struct timeval) { 1, 0 }))); ++ ++ return 0; ++} ++ ++#include +diff --git a/sunrpc/tst-udp-nonblocking.c b/sunrpc/tst-udp-nonblocking.c +new file mode 100644 +index 0000000000..1d6a7f4b56 +--- /dev/null ++++ b/sunrpc/tst-udp-nonblocking.c +@@ -0,0 +1,333 @@ ++/* Test non-blocking use of the UDP client. ++ Copyright (C) 2017 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Test data serialization and deserialization. */ ++ ++struct test_query ++{ ++ uint32_t a; ++ uint32_t b; ++ uint32_t timeout_ms; ++}; ++ ++static bool_t ++xdr_test_query (XDR *xdrs, void *data, ...) ++{ ++ struct test_query *p = data; ++ return xdr_uint32_t (xdrs, &p->a) ++ && xdr_uint32_t (xdrs, &p->b) ++ && xdr_uint32_t (xdrs, &p->timeout_ms); ++} ++ ++struct test_response ++{ ++ uint32_t server_id; ++ uint32_t seq; ++ uint32_t sum; ++}; ++ ++static bool_t ++xdr_test_response (XDR *xdrs, void *data, ...) ++{ ++ struct test_response *p = data; ++ return xdr_uint32_t (xdrs, &p->server_id) ++ && xdr_uint32_t (xdrs, &p->seq) ++ && xdr_uint32_t (xdrs, &p->sum); ++} ++ ++/* Implementation of the test server. */ ++ ++enum ++ { ++ /* Number of test servers to run. */ ++ SERVER_COUNT = 3, ++ ++ /* RPC parameters, chosen at random. */ ++ PROGNUM = 8242, ++ VERSNUM = 19654, ++ ++ /* Main RPC operation. */ ++ PROC_ADD = 1, ++ ++ /* Request process termination. */ ++ PROC_EXIT, ++ ++ /* Special exit status to mark successful processing. */ ++ EXIT_MARKER = 55, ++ }; ++ ++/* Set by the parent process to tell test servers apart. */ ++static int server_id; ++ ++/* Implementation of the test server. */ ++static void ++server_dispatch (struct svc_req *request, SVCXPRT *transport) ++{ ++ /* Query sequence number. */ ++ static uint32_t seq = 0; ++ ++seq; ++ static bool proc_add_seen; ++ ++ if (test_verbose) ++ printf ("info: server_dispatch server_id=%d seq=%u rq_proc=%lu\n", ++ server_id, seq, request->rq_proc); ++ ++ switch (request->rq_proc) ++ { ++ case PROC_ADD: ++ { ++ struct test_query query; ++ memset (&query, 0xc0, sizeof (query)); ++ TEST_VERIFY_EXIT ++ (svc_getargs (transport, xdr_test_query, ++ (void *) &query)); ++ ++ if (test_verbose) ++ printf (" a=%u b=%u timeout_ms=%u\n", ++ query.a, query.b, query.timeout_ms); ++ ++ usleep (query.timeout_ms * 1000); ++ ++ struct test_response response = ++ { ++ .server_id = server_id, ++ .seq = seq, ++ .sum = query.a + query.b, ++ }; ++ TEST_VERIFY (svc_sendreply (transport, xdr_test_response, ++ (void *) &response)); ++ if (test_verbose) ++ printf (" server id %d response seq=%u sent\n", server_id, seq); ++ proc_add_seen = true; ++ } ++ break; ++ ++ case PROC_EXIT: ++ TEST_VERIFY (proc_add_seen); ++ TEST_VERIFY (svc_sendreply (transport, (xdrproc_t) xdr_void, NULL)); ++ _exit (EXIT_MARKER); ++ break; ++ ++ default: ++ FAIL_EXIT1 ("invalid rq_proc value: %lu", request->rq_proc); ++ break; ++ } ++} ++ ++/* Return the number seconds since an arbitrary point in time. */ ++static double ++get_ticks (void) ++{ ++ { ++ struct timespec ts; ++ if (clock_gettime (CLOCK_MONOTONIC, &ts) == 0) ++ return ts.tv_sec + ts.tv_nsec * 1e-9; ++ } ++ { ++ struct timeval tv; ++ TEST_VERIFY_EXIT (gettimeofday (&tv, NULL) == 0); ++ return tv.tv_sec + tv.tv_usec * 1e-6; ++ } ++} ++ ++static int ++do_test (void) ++{ ++ support_become_root (); ++ support_enter_network_namespace (); ++ ++ /* Information about the test servers. */ ++ struct ++ { ++ SVCXPRT *transport; ++ struct sockaddr_in address; ++ pid_t pid; ++ uint32_t xid; ++ } servers[SERVER_COUNT]; ++ ++ /* Spawn the test servers. */ ++ for (int i = 0; i < SERVER_COUNT; ++i) ++ { ++ servers[i].transport = svcudp_create (RPC_ANYSOCK); ++ TEST_VERIFY_EXIT (servers[i].transport != NULL); ++ servers[i].address = (struct sockaddr_in) ++ { ++ .sin_family = AF_INET, ++ .sin_addr.s_addr = htonl (INADDR_LOOPBACK), ++ .sin_port = htons (servers[i].transport->xp_port), ++ }; ++ servers[i].xid = 0xabcd0101 + i; ++ if (test_verbose) ++ printf ("info: setting up server %d xid=%x on port %d\n", ++ i, servers[i].xid, servers[i].transport->xp_port); ++ ++ server_id = i; ++ servers[i].pid = xfork (); ++ if (servers[i].pid == 0) ++ { ++ TEST_VERIFY (svc_register (servers[i].transport, ++ PROGNUM, VERSNUM, server_dispatch, 0)); ++ svc_run (); ++ FAIL_EXIT1 ("supposed to be unreachable"); ++ } ++ /* We need to close the socket so that we do not accidentally ++ consume the request. */ ++ TEST_VERIFY (close (servers[i].transport->xp_sock) == 0); ++ } ++ ++ ++ /* The following code mirrors what ypbind does. */ ++ ++ /* Copied from clnt_udp.c (like ypbind). */ ++ struct cu_data ++ { ++ int cu_sock; ++ bool_t cu_closeit; ++ struct sockaddr_in cu_raddr; ++ int cu_rlen; ++ struct timeval cu_wait; ++ struct timeval cu_total; ++ struct rpc_err cu_error; ++ XDR cu_outxdrs; ++ u_int cu_xdrpos; ++ u_int cu_sendsz; ++ char *cu_outbuf; ++ u_int cu_recvsz; ++ char cu_inbuf[1]; ++ }; ++ ++ int client_socket = xsocket (AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0); ++ CLIENT *clnt = clntudp_create (&servers[0].address, PROGNUM, VERSNUM, ++ /* 5 seconds per-response timeout. */ ++ ((struct timeval) { 5, 0 }), ++ &client_socket); ++ TEST_VERIFY (clnt != NULL); ++ clnt->cl_auth = authunix_create_default (); ++ { ++ struct timeval zero = { 0, 0 }; ++ TEST_VERIFY (clnt_control (clnt, CLSET_TIMEOUT, (void *) &zero)); ++ } ++ ++ /* Poke at internal data structures (like ypbind). */ ++ struct cu_data *cu = (struct cu_data *) clnt->cl_private; ++ ++ /* Send a ping to each server. */ ++ double before_pings = get_ticks (); ++ for (int i = 0; i < SERVER_COUNT; ++i) ++ { ++ if (test_verbose) ++ printf ("info: sending server %d ping\n", i); ++ /* Reset the xid because it is changed by each invocation of ++ clnt_call. Subtract one to compensate for the xid update ++ during the call. */ ++ *((u_int32_t *) (cu->cu_outbuf)) = servers[i].xid - 1; ++ cu->cu_raddr = servers[i].address; ++ ++ struct test_query query = { .a = 100, .b = i + 1 }; ++ if (i == 1) ++ /* Shorter timeout to prefer this server. These timeouts must ++ be much shorter than the 5-second per-response timeout ++ configured with clntudp_create. */ ++ query.timeout_ms = 700; ++ else ++ query.timeout_ms = 1400; ++ struct test_response response = { 0 }; ++ /* NB: Do not check the return value. The server reply will ++ prove that the call worked. */ ++ double before_one_ping = get_ticks (); ++ clnt_call (clnt, PROC_ADD, ++ xdr_test_query, (void *) &query, ++ xdr_test_response, (void *) &response, ++ ((struct timeval) { 0, 0 })); ++ double after_one_ping = get_ticks (); ++ if (test_verbose) ++ printf ("info: non-blocking send took %f seconds\n", ++ after_one_ping - before_one_ping); ++ /* clnt_call should return immediately. Accept some delay in ++ case the process is descheduled. */ ++ TEST_VERIFY (after_one_ping - before_one_ping < 0.3); ++ } ++ ++ /* Collect the non-blocking response. */ ++ if (test_verbose) ++ printf ("info: collecting response\n"); ++ struct test_response response = { 0 }; ++ TEST_VERIFY ++ (clnt_call (clnt, PROC_ADD, NULL, NULL, ++ xdr_test_response, (void *) &response, ++ ((struct timeval) { 0, 0 })) == RPC_SUCCESS); ++ double after_pings = get_ticks (); ++ if (test_verbose) ++ printf ("info: send/receive took %f seconds\n", ++ after_pings - before_pings); ++ /* Expected timeout is 0.7 seconds. */ ++ TEST_VERIFY (0.7 <= after_pings - before_pings); ++ TEST_VERIFY (after_pings - before_pings < 1.2); ++ ++ uint32_t xid; ++ memcpy (&xid, &cu->cu_inbuf, sizeof (xid)); ++ if (test_verbose) ++ printf ("info: non-blocking response: xid=%x server_id=%u seq=%u sum=%u\n", ++ xid, response.server_id, response.seq, response.sum); ++ /* Check that the reply from the preferred server was used. */ ++ TEST_VERIFY (servers[1].xid == xid); ++ TEST_VERIFY (response.server_id == 1); ++ TEST_VERIFY (response.seq == 1); ++ TEST_VERIFY (response.sum == 102); ++ ++ auth_destroy (clnt->cl_auth); ++ clnt_destroy (clnt); ++ ++ for (int i = 0; i < SERVER_COUNT; ++i) ++ { ++ if (test_verbose) ++ printf ("info: requesting server %d termination\n", i); ++ client_socket = RPC_ANYSOCK; ++ clnt = clntudp_create (&servers[i].address, PROGNUM, VERSNUM, ++ ((struct timeval) { 5, 0 }), ++ &client_socket); ++ TEST_VERIFY_EXIT (clnt != NULL); ++ TEST_VERIFY (clnt_call (clnt, PROC_EXIT, ++ (xdrproc_t) xdr_void, NULL, ++ (xdrproc_t) xdr_void, NULL, ++ ((struct timeval) { 3, 0 })) == RPC_SUCCESS); ++ clnt_destroy (clnt); ++ ++ int status; ++ xwaitpid (servers[i].pid, &status, 0); ++ TEST_VERIFY (WIFEXITED (status) && WEXITSTATUS (status) == EXIT_MARKER); ++ } ++ ++ return 0; ++} ++ ++#include +diff --git a/sunrpc/tst-udp-timeout.c b/sunrpc/tst-udp-timeout.c +new file mode 100644 +index 0000000000..db9943a03e +--- /dev/null ++++ b/sunrpc/tst-udp-timeout.c +@@ -0,0 +1,402 @@ ++/* Test timeout handling in the UDP client. ++ Copyright (C) 2017 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Test data serialization and deserialization. */ ++ ++struct test_query ++{ ++ uint32_t a; ++ uint32_t b; ++ uint32_t timeout_ms; ++ uint32_t wait_for_seq; ++ uint32_t garbage_packets; ++}; ++ ++static bool_t ++xdr_test_query (XDR *xdrs, void *data, ...) ++{ ++ struct test_query *p = data; ++ return xdr_uint32_t (xdrs, &p->a) ++ && xdr_uint32_t (xdrs, &p->b) ++ && xdr_uint32_t (xdrs, &p->timeout_ms) ++ && xdr_uint32_t (xdrs, &p->wait_for_seq) ++ && xdr_uint32_t (xdrs, &p->garbage_packets); ++} ++ ++struct test_response ++{ ++ uint32_t seq; ++ uint32_t sum; ++}; ++ ++static bool_t ++xdr_test_response (XDR *xdrs, void *data, ...) ++{ ++ struct test_response *p = data; ++ return xdr_uint32_t (xdrs, &p->seq) ++ && xdr_uint32_t (xdrs, &p->sum); ++} ++ ++/* Implementation of the test server. */ ++ ++enum ++ { ++ /* RPC parameters, chosen at random. */ ++ PROGNUM = 15717, ++ VERSNUM = 13689, ++ ++ /* Main RPC operation. */ ++ PROC_ADD = 1, ++ ++ /* Reset the sequence number. */ ++ PROC_RESET_SEQ, ++ ++ /* Request process termination. */ ++ PROC_EXIT, ++ ++ /* Special exit status to mark successful processing. */ ++ EXIT_MARKER = 55, ++ }; ++ ++static void ++server_dispatch (struct svc_req *request, SVCXPRT *transport) ++{ ++ /* Query sequence number. */ ++ static uint32_t seq = 0; ++ ++seq; ++ ++ if (test_verbose) ++ printf ("info: server_dispatch seq=%u rq_proc=%lu\n", ++ seq, request->rq_proc); ++ ++ switch (request->rq_proc) ++ { ++ case PROC_ADD: ++ { ++ struct test_query query; ++ memset (&query, 0xc0, sizeof (query)); ++ TEST_VERIFY_EXIT ++ (svc_getargs (transport, xdr_test_query, ++ (void *) &query)); ++ ++ if (test_verbose) ++ printf (" a=%u b=%u timeout_ms=%u wait_for_seq=%u" ++ " garbage_packets=%u\n", ++ query.a, query.b, query.timeout_ms, query.wait_for_seq, ++ query.garbage_packets); ++ ++ if (seq < query.wait_for_seq) ++ { ++ /* No response at this point. */ ++ if (test_verbose) ++ printf (" skipped response\n"); ++ break; ++ } ++ ++ if (query.garbage_packets > 0) ++ { ++ int per_packet_timeout; ++ if (query.timeout_ms > 0) ++ per_packet_timeout ++ = query.timeout_ms * 1000 / query.garbage_packets; ++ else ++ per_packet_timeout = 0; ++ ++ char buf[20]; ++ memset (&buf, 0xc0, sizeof (buf)); ++ for (int i = 0; i < query.garbage_packets; ++i) ++ { ++ /* 13 is relatively prime to 20 = sizeof (buf) + 1, so ++ the len variable will cover the entire interval ++ [0, 20] if query.garbage_packets is sufficiently ++ large. */ ++ size_t len = (i * 13 + 1) % (sizeof (buf) + 1); ++ TEST_VERIFY (sendto (transport->xp_sock, ++ buf, len, MSG_NOSIGNAL, ++ (struct sockaddr *) &transport->xp_raddr, ++ transport->xp_addrlen) == len); ++ if (per_packet_timeout > 0) ++ usleep (per_packet_timeout); ++ } ++ } ++ else if (query.timeout_ms > 0) ++ usleep (query.timeout_ms * 1000); ++ ++ struct test_response response = ++ { ++ .seq = seq, ++ .sum = query.a + query.b, ++ }; ++ TEST_VERIFY (svc_sendreply (transport, xdr_test_response, ++ (void *) &response)); ++ } ++ break; ++ ++ case PROC_RESET_SEQ: ++ seq = 0; ++ TEST_VERIFY (svc_sendreply (transport, (xdrproc_t) xdr_void, NULL)); ++ break; ++ ++ case PROC_EXIT: ++ TEST_VERIFY (svc_sendreply (transport, (xdrproc_t) xdr_void, NULL)); ++ _exit (EXIT_MARKER); ++ break; ++ ++ default: ++ FAIL_EXIT1 ("invalid rq_proc value: %lu", request->rq_proc); ++ break; ++ } ++} ++ ++/* Implementation of the test client. */ ++ ++static struct test_response ++test_call (CLIENT *clnt, int proc, struct test_query query, ++ struct timeval timeout) ++{ ++ if (test_verbose) ++ printf ("info: test_call proc=%d timeout=%lu.%06lu\n", ++ proc, (unsigned long) timeout.tv_sec, ++ (unsigned long) timeout.tv_usec); ++ struct test_response response; ++ TEST_VERIFY_EXIT (clnt_call (clnt, proc, ++ xdr_test_query, (void *) &query, ++ xdr_test_response, (void *) &response, ++ timeout) ++ == RPC_SUCCESS); ++ return response; ++} ++ ++static void ++test_call_timeout (CLIENT *clnt, int proc, struct test_query query, ++ struct timeval timeout) ++{ ++ struct test_response response; ++ TEST_VERIFY (clnt_call (clnt, proc, ++ xdr_test_query, (void *) &query, ++ xdr_test_response, (void *) &response, ++ timeout) ++ == RPC_TIMEDOUT); ++} ++ ++/* Complete one regular RPC call to drain the server socket ++ buffer. Resets the sequence number. */ ++static void ++test_call_flush (CLIENT *clnt) ++{ ++ /* This needs a longer timeout to flush out all pending requests. ++ The choice of 5 seconds is larger than the per-response timeouts ++ requested via the timeout_ms field. */ ++ if (test_verbose) ++ printf ("info: flushing pending queries\n"); ++ TEST_VERIFY_EXIT (clnt_call (clnt, PROC_RESET_SEQ, ++ (xdrproc_t) xdr_void, NULL, ++ (xdrproc_t) xdr_void, NULL, ++ ((struct timeval) { 5, 0 })) ++ == RPC_SUCCESS); ++} ++ ++/* Return the number seconds since an arbitrary point in time. */ ++static double ++get_ticks (void) ++{ ++ { ++ struct timespec ts; ++ if (clock_gettime (CLOCK_MONOTONIC, &ts) == 0) ++ return ts.tv_sec + ts.tv_nsec * 1e-9; ++ } ++ { ++ struct timeval tv; ++ TEST_VERIFY_EXIT (gettimeofday (&tv, NULL) == 0); ++ return tv.tv_sec + tv.tv_usec * 1e-6; ++ } ++} ++ ++static void ++test_udp_server (int port) ++{ ++ struct sockaddr_in sin = ++ { ++ .sin_family = AF_INET, ++ .sin_addr.s_addr = htonl (INADDR_LOOPBACK), ++ .sin_port = htons (port) ++ }; ++ int sock = RPC_ANYSOCK; ++ ++ /* The client uses a 1.5 second timeout for retries. The timeouts ++ are arbitrary, but chosen so that there is a substantial gap ++ between them, but the total time spent waiting is not too ++ large. */ ++ CLIENT *clnt = clntudp_create (&sin, PROGNUM, VERSNUM, ++ (struct timeval) { 1, 500 * 1000 }, ++ &sock); ++ TEST_VERIFY_EXIT (clnt != NULL); ++ ++ /* Basic call/response test. */ ++ struct test_response response = test_call ++ (clnt, PROC_ADD, ++ (struct test_query) { .a = 17, .b = 4 }, ++ (struct timeval) { 3, 0 }); ++ TEST_VERIFY (response.sum == 21); ++ TEST_VERIFY (response.seq == 1); ++ ++ /* Check that garbage packets do not interfere with timeout ++ processing. */ ++ double before = get_ticks (); ++ response = test_call ++ (clnt, PROC_ADD, ++ (struct test_query) { ++ .a = 19, .b = 4, .timeout_ms = 500, .garbage_packets = 21, ++ }, ++ (struct timeval) { 3, 0 }); ++ TEST_VERIFY (response.sum == 23); ++ TEST_VERIFY (response.seq == 2); ++ double after = get_ticks (); ++ if (test_verbose) ++ printf ("info: 21 garbage packets took %f seconds\n", after - before); ++ /* Expected timeout is 0.5 seconds. Add some slack in case process ++ scheduling delays processing the query or response, but do not ++ accept a retry (which would happen at 1.5 seconds). */ ++ TEST_VERIFY (0.5 <= after - before); ++ TEST_VERIFY (after - before < 1.2); ++ test_call_flush (clnt); ++ ++ /* Check that missing a response introduces a 1.5 second timeout, as ++ requested when calling clntudp_create. */ ++ before = get_ticks (); ++ response = test_call ++ (clnt, PROC_ADD, ++ (struct test_query) { .a = 170, .b = 40, .wait_for_seq = 2 }, ++ (struct timeval) { 3, 0 }); ++ TEST_VERIFY (response.sum == 210); ++ TEST_VERIFY (response.seq == 2); ++ after = get_ticks (); ++ if (test_verbose) ++ printf ("info: skipping one response took %f seconds\n", ++ after - before); ++ /* Expected timeout is 1.5 seconds. Do not accept a second retry ++ (which would happen at 3 seconds). */ ++ TEST_VERIFY (1.5 <= after - before); ++ TEST_VERIFY (after - before < 2.9); ++ test_call_flush (clnt); ++ ++ /* Check that the overall timeout wins against the per-query ++ timeout. */ ++ before = get_ticks (); ++ test_call_timeout ++ (clnt, PROC_ADD, ++ (struct test_query) { .a = 170, .b = 41, .wait_for_seq = 2 }, ++ (struct timeval) { 0, 750 * 1000 }); ++ after = get_ticks (); ++ if (test_verbose) ++ printf ("info: 0.75 second timeout took %f seconds\n", ++ after - before); ++ TEST_VERIFY (0.75 <= after - before); ++ TEST_VERIFY (after - before < 1.4); ++ test_call_flush (clnt); ++ ++ for (int with_garbage = 0; with_garbage < 2; ++with_garbage) ++ { ++ /* Check that no response at all causes the client to bail out. */ ++ before = get_ticks (); ++ test_call_timeout ++ (clnt, PROC_ADD, ++ (struct test_query) { ++ .a = 170, .b = 40, .timeout_ms = 1200, ++ .garbage_packets = with_garbage * 21 ++ }, ++ (struct timeval) { 0, 750 * 1000 }); ++ after = get_ticks (); ++ if (test_verbose) ++ printf ("info: test_udp_server: 0.75 second timeout took %f seconds" ++ " (garbage %d)\n", ++ after - before, with_garbage); ++ TEST_VERIFY (0.75 <= after - before); ++ TEST_VERIFY (after - before < 1.4); ++ test_call_flush (clnt); ++ ++ /* As above, but check the total timeout. */ ++ before = get_ticks (); ++ test_call_timeout ++ (clnt, PROC_ADD, ++ (struct test_query) { ++ .a = 170, .b = 40, .timeout_ms = 3000, ++ .garbage_packets = with_garbage * 30 ++ }, ++ (struct timeval) { 2, 300 * 1000 }); ++ after = get_ticks (); ++ if (test_verbose) ++ printf ("info: test_udp_server: 2.3 second timeout took %f seconds" ++ " (garbage %d)\n", ++ after - before, with_garbage); ++ TEST_VERIFY (2.3 <= after - before); ++ TEST_VERIFY (after - before < 3.0); ++ test_call_flush (clnt); ++ } ++ ++ TEST_VERIFY_EXIT (clnt_call (clnt, PROC_EXIT, ++ (xdrproc_t) xdr_void, NULL, ++ (xdrproc_t) xdr_void, NULL, ++ ((struct timeval) { 5, 0 })) ++ == RPC_SUCCESS); ++ clnt_destroy (clnt); ++} ++ ++static int ++do_test (void) ++{ ++ support_become_root (); ++ support_enter_network_namespace (); ++ ++ SVCXPRT *transport = svcudp_create (RPC_ANYSOCK); ++ TEST_VERIFY_EXIT (transport != NULL); ++ TEST_VERIFY (svc_register (transport, PROGNUM, VERSNUM, server_dispatch, 0)); ++ ++ pid_t pid = xfork (); ++ if (pid == 0) ++ { ++ svc_run (); ++ FAIL_EXIT1 ("supposed to be unreachable"); ++ } ++ test_udp_server (transport->xp_port); ++ ++ int status; ++ xwaitpid (pid, &status, 0); ++ TEST_VERIFY (WIFEXITED (status) && WEXITSTATUS (status) == EXIT_MARKER); ++ ++ SVC_DESTROY (transport); ++ return 0; ++} ++ ++/* The minimum run time is around 17 seconds. */ ++#define TIMEOUT 25 ++#include +diff --git a/support/Makefile b/support/Makefile +index 2ace559ae0..027a663000 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -35,7 +35,12 @@ libsupport-routines = \ + oom_error \ + resolv_test \ + set_fortify_handler \ ++ support-xstat \ + support_become_root \ ++ support_can_chroot \ ++ support_capture_subprocess \ ++ support_capture_subprocess_check \ ++ support_chroot \ + support_enter_network_namespace \ + support_format_address_family \ + support_format_addrinfo \ +@@ -43,17 +48,25 @@ libsupport-routines = \ + support_format_herrno \ + support_format_hostent \ + support_format_netent \ ++ support_isolate_in_subprocess \ + support_record_failure \ + support_run_diff \ ++ support_shared_allocate \ ++ support_write_file_string \ + support_test_main \ + support_test_verify_impl \ + temp_file \ + write_message \ + xaccept \ ++ xaccept4 \ + xasprintf \ + xbind \ + xcalloc \ ++ xchroot \ ++ xclose \ + xconnect \ ++ xdlfcn \ ++ xdup2 \ + xfclose \ + xfopen \ + xfork \ +@@ -61,13 +74,18 @@ libsupport-routines = \ + xlisten \ + xmalloc \ + xmemstream \ ++ xmkdir \ + xmmap \ ++ xmprotect \ + xmunmap \ ++ xopen \ ++ xpipe \ + xpoll \ + xpthread_attr_destroy \ + xpthread_attr_init \ + xpthread_attr_setdetachstate \ + xpthread_attr_setstacksize \ ++ xpthread_attr_setguardsize \ + xpthread_barrier_destroy \ + xpthread_barrier_init \ + xpthread_barrier_wait \ +@@ -89,6 +107,12 @@ libsupport-routines = \ + xpthread_mutexattr_setrobust \ + xpthread_mutexattr_settype \ + xpthread_once \ ++ xpthread_rwlock_init \ ++ xpthread_rwlock_rdlock \ ++ xpthread_rwlock_wrlock \ ++ xpthread_rwlock_unlock \ ++ xpthread_rwlockattr_init \ ++ xpthread_rwlockattr_setkind_np \ + xpthread_sigmask \ + xpthread_spin_lock \ + xpthread_spin_unlock \ +@@ -111,6 +135,8 @@ endif + tests = \ + README-testing \ + tst-support-namespace \ ++ tst-support_capture_subprocess \ ++ tst-support_format_dns_packet \ + tst-support_record_failure \ + + ifeq ($(run-built-tests),yes) +@@ -125,4 +151,6 @@ $(objpfx)tst-support_record_failure-2.out: tst-support_record_failure-2.sh \ + $(evaluate-test) + endif + ++$(objpfx)tst-support_format_dns_packet: $(common-objpfx)resolv/libresolv.so ++ + include ../Rules +diff --git a/support/capture_subprocess.h b/support/capture_subprocess.h +new file mode 100644 +index 0000000000..43caf9bce4 +--- /dev/null ++++ b/support/capture_subprocess.h +@@ -0,0 +1,61 @@ ++/* Capture output from a subprocess. ++ Copyright (C) 2017 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 ++ . */ ++ ++#ifndef SUPPORT_CAPTURE_SUBPROCESS_H ++#define SUPPORT_CAPTURE_SUBPROCESS_H ++ ++#include ++ ++struct support_capture_subprocess ++{ ++ struct xmemstream out; ++ struct xmemstream err; ++ int status; ++}; ++ ++/* Invoke CALLBACK (CLOSURE) in a subprocess and capture standard ++ output, standard error, and the exit status. The out.buffer and ++ err.buffer members in the result are null-terminated strings which ++ can be examined by the caller (out.out and err.out are NULL). */ ++struct support_capture_subprocess support_capture_subprocess ++ (void (*callback) (void *), void *closure); ++ ++/* Deallocate the subprocess data captured by ++ support_capture_subprocess. */ ++void support_capture_subprocess_free (struct support_capture_subprocess *); ++ ++enum support_capture_allow ++{ ++ /* No output is allowed. */ ++ sc_allow_none = 0x01, ++ /* Output to stdout is permitted. */ ++ sc_allow_stdout = 0x02, ++ /* Output to standard error is permitted. */ ++ sc_allow_stderr = 0x04, ++}; ++ ++/* Check that the subprocess exited with STATUS and that only the ++ allowed outputs happened. ALLOWED is a combination of ++ support_capture_allow flags. Report errors under the CONTEXT ++ message. */ ++void support_capture_subprocess_check (struct support_capture_subprocess *, ++ const char *context, int status, ++ int allowed) ++ __attribute__ ((nonnull (1, 2))); ++ ++#endif /* SUPPORT_CAPTURE_SUBPROCESS_H */ +diff --git a/support/check.h b/support/check.h +index 1d244a3557..bdcd12952a 100644 +--- a/support/check.h ++++ b/support/check.h +@@ -51,7 +51,7 @@ __BEGIN_DECLS + if (expr) \ + ; \ + else \ +- support_test_verify_impl (-1, __FILE__, __LINE__, #expr); \ ++ support_test_verify_impl (__FILE__, __LINE__, #expr); \ + }) + + /* Record a test failure and exit if EXPR evaluates to false. */ +@@ -60,7 +60,8 @@ __BEGIN_DECLS + if (expr) \ + ; \ + else \ +- support_test_verify_impl (1, __FILE__, __LINE__, #expr); \ ++ support_test_verify_exit_impl \ ++ (1, __FILE__, __LINE__, #expr); \ + }) + + int support_print_failure_impl (const char *file, int line, +@@ -70,8 +71,11 @@ void support_exit_failure_impl (int exit_status, + const char *file, int line, + const char *format, ...) + __attribute__ ((noreturn, nonnull (2), format (printf, 4, 5))); +-void support_test_verify_impl (int status, const char *file, int line, ++void support_test_verify_impl (const char *file, int line, + const char *expr); ++void support_test_verify_exit_impl (int status, const char *file, int line, ++ const char *expr) ++ __attribute__ ((noreturn)); + + /* Record a test failure. This function returns and does not + terminate the process. The failure counter is stored in a shared +diff --git a/support/namespace.h b/support/namespace.h +index 6bc82d619b..9eddb1a0e9 100644 +--- a/support/namespace.h ++++ b/support/namespace.h +@@ -35,6 +35,13 @@ __BEGIN_DECLS + single-threaded processes. */ + bool support_become_root (void); + ++/* Return true if this process can perform a chroot operation. In ++ general, this is only possible if support_become_root has been ++ called. Note that the actual test is performed in a subprocess, ++ after fork, so that the file system root of the original process is ++ not changed. */ ++bool support_can_chroot (void); ++ + /* Enter a network namespace (and a UTS namespace if possible) and + configure the loopback interface. Return true if a network + namespace could be created. Print diagnostics to standard output. +@@ -48,6 +55,48 @@ bool support_enter_network_namespace (void); + UTS namespace. */ + bool support_in_uts_namespace (void); + ++/* Invoke CALLBACK (CLOSURE) in a subprocess created using fork. ++ Terminate the calling process if the subprocess exits with a ++ non-zero exit status. */ ++void support_isolate_in_subprocess (void (*callback) (void *), void *closure); ++ ++/* Describe the setup of a chroot environment, for ++ support_chroot_create below. */ ++struct support_chroot_configuration ++{ ++ /* File contents. The files are not created if the field is ++ NULL. */ ++ const char *resolv_conf; /* /etc/resolv.conf. */ ++ const char *hosts; /* /etc/hosts. */ ++ const char *host_conf; /* /etc/host.conf. */ ++}; ++ ++/* The result of the creation of a chroot. */ ++struct support_chroot ++{ ++ /* Path information. All these paths are relative to the parent ++ chroot. */ ++ ++ /* Path to the chroot directory. */ ++ char *path_chroot; ++ ++ /* Paths to files in the chroot. These are absolute and outside of ++ the chroot. */ ++ char *path_resolv_conf; /* /etc/resolv.conf. */ ++ char *path_hosts; /* /etc/hosts. */ ++ char *path_host_conf; /* /etc/host.conf. */ ++}; ++ ++/* Create a chroot environment. The returned data should be freed ++ using support_chroot_free below. The files will be deleted when ++ the process exits. This function does not enter the chroot. */ ++struct support_chroot *support_chroot_create ++ (struct support_chroot_configuration); ++ ++/* Deallocate the chroot information created by ++ support_chroot_create. */ ++void support_chroot_free (struct support_chroot *); ++ + __END_DECLS + + #endif +diff --git a/support/resolv_test.c b/support/resolv_test.c +index 2d0ea3c17c..1625dcf43a 100644 +--- a/support/resolv_test.c ++++ b/support/resolv_test.c +@@ -32,9 +32,11 @@ + #include + #include + #include ++#include ++#include + #include + +-/* Response builder. */ ++/* Response builder. */ + + enum + { +@@ -428,6 +430,7 @@ struct query_info + char qname[MAXDNAME]; + uint16_t qclass; + uint16_t qtype; ++ struct resolv_edns_info edns; + }; + + /* Update *INFO from the specified DNS packet. */ +@@ -435,10 +438,26 @@ static void + parse_query (struct query_info *info, + const unsigned char *buffer, size_t length) + { +- if (length < 12) ++ HEADER hd; ++ _Static_assert (sizeof (hd) == 12, "DNS header size"); ++ if (length < sizeof (hd)) + FAIL_EXIT1 ("malformed DNS query: too short: %zu bytes", length); +- +- int ret = dn_expand (buffer, buffer + length, buffer + 12, ++ memcpy (&hd, buffer, sizeof (hd)); ++ ++ if (ntohs (hd.qdcount) != 1) ++ FAIL_EXIT1 ("malformed DNS query: wrong question count: %d", ++ (int) ntohs (hd.qdcount)); ++ if (ntohs (hd.ancount) != 0) ++ FAIL_EXIT1 ("malformed DNS query: wrong answer count: %d", ++ (int) ntohs (hd.ancount)); ++ if (ntohs (hd.nscount) != 0) ++ FAIL_EXIT1 ("malformed DNS query: wrong authority count: %d", ++ (int) ntohs (hd.nscount)); ++ if (ntohs (hd.arcount) > 1) ++ FAIL_EXIT1 ("malformed DNS query: wrong additional count: %d", ++ (int) ntohs (hd.arcount)); ++ ++ int ret = dn_expand (buffer, buffer + length, buffer + sizeof (hd), + info->qname, sizeof (info->qname)); + if (ret < 0) + FAIL_EXIT1 ("malformed DNS query: cannot uncompress QNAME"); +@@ -456,6 +475,37 @@ parse_query (struct query_info *info, + memcpy (&qtype_qclass, buffer + 12 + ret, sizeof (qtype_qclass)); + info->qclass = ntohs (qtype_qclass.qclass); + info->qtype = ntohs (qtype_qclass.qtype); ++ ++ memset (&info->edns, 0, sizeof (info->edns)); ++ if (ntohs (hd.arcount) > 0) ++ { ++ /* Parse EDNS record. */ ++ struct __attribute__ ((packed, aligned (1))) ++ { ++ uint8_t root; ++ uint16_t rtype; ++ uint16_t payload; ++ uint8_t edns_extended_rcode; ++ uint8_t edns_version; ++ uint16_t flags; ++ uint16_t rdatalen; ++ } rr; ++ _Static_assert (sizeof (rr) == 11, "EDNS record size"); ++ ++ if (remaining < 4 + sizeof (rr)) ++ FAIL_EXIT1 ("mailformed DNS query: no room for EDNS record"); ++ memcpy (&rr, buffer + 12 + ret + 4, sizeof (rr)); ++ if (rr.root != 0) ++ FAIL_EXIT1 ("malformed DNS query: invalid OPT RNAME: %d\n", rr.root); ++ if (rr.rtype != htons (41)) ++ FAIL_EXIT1 ("malformed DNS query: invalid OPT type: %d\n", ++ ntohs (rr.rtype)); ++ info->edns.active = true; ++ info->edns.extended_rcode = rr.edns_extended_rcode; ++ info->edns.version = rr.edns_version; ++ info->edns.flags = ntohs (rr.flags); ++ info->edns.payload_size = ntohs (rr.payload); ++ } + } + + +@@ -585,6 +635,7 @@ server_thread_udp_process_one (struct resolv_test *obj, int server_index) + .query_length = length, + .server_index = server_index, + .tcp = false, ++ .edns = qinfo.edns, + }; + struct resolv_response_builder *b = response_builder_allocate (query, length); + obj->config.response_callback +@@ -820,6 +871,7 @@ server_thread_tcp_client (void *arg) + .query_length = query_length, + .server_index = closure->server_index, + .tcp = true, ++ .edns = qinfo.edns, + }; + struct resolv_response_builder *b = response_builder_allocate + (query_buffer, query_length); +@@ -860,7 +912,7 @@ server_thread_tcp_client (void *arg) + break; + } + +- close (closure->client_socket); ++ xclose (closure->client_socket); + free (closure); + return NULL; + } +@@ -881,7 +933,7 @@ server_thread_tcp (struct resolv_test *obj, int server_index) + if (obj->termination_requested) + { + xpthread_mutex_unlock (&obj->lock); +- close (client_socket); ++ xclose (client_socket); + break; + } + xpthread_mutex_unlock (&obj->lock); +@@ -941,8 +993,8 @@ make_server_sockets (struct resolv_test_server *server) + next local UDP address randomly. */ + if (errno == EADDRINUSE) + { +- close (server->socket_udp); +- close (server->socket_tcp); ++ xclose (server->socket_udp); ++ xclose (server->socket_tcp); + continue; + } + FAIL_EXIT1 ("TCP bind: %m"); +@@ -952,6 +1004,29 @@ make_server_sockets (struct resolv_test_server *server) + } + } + ++/* Like make_server_sockets, but the caller supplies the address to ++ use. */ ++static void ++make_server_sockets_for_address (struct resolv_test_server *server, ++ const struct sockaddr *addr) ++{ ++ server->socket_udp = xsocket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); ++ server->socket_tcp = xsocket (AF_INET, SOCK_STREAM, IPPROTO_TCP); ++ ++ if (addr->sa_family == AF_INET) ++ server->address = *(const struct sockaddr_in *) addr; ++ else ++ /* We cannot store the server address in the socket. This should ++ not matter if disable_redirect is used. */ ++ server->address = (struct sockaddr_in) { .sin_family = 0, }; ++ ++ xbind (server->socket_udp, ++ (struct sockaddr *)&server->address, sizeof (server->address)); ++ xbind (server->socket_tcp, ++ (struct sockaddr *)&server->address, sizeof (server->address)); ++ xlisten (server->socket_tcp, 5); ++} ++ + /* One-time initialization of NSS. */ + static void + resolv_redirect_once (void) +@@ -1012,11 +1087,17 @@ resolv_test_start (struct resolv_redirect_config config) + .lock = PTHREAD_MUTEX_INITIALIZER, + }; + +- resolv_test_init (); ++ if (!config.disable_redirect) ++ resolv_test_init (); + + /* Create all the servers, to reserve the necessary ports. */ + for (int server_index = 0; server_index < config.nscount; ++server_index) +- make_server_sockets (obj->servers + server_index); ++ if (config.disable_redirect && config.server_address_overrides != NULL) ++ make_server_sockets_for_address ++ (obj->servers + server_index, ++ config.server_address_overrides[server_index]); ++ else ++ make_server_sockets (obj->servers + server_index); + + /* Start server threads. Disable the server ports, as + requested. */ +@@ -1025,7 +1106,7 @@ resolv_test_start (struct resolv_redirect_config config) + struct resolv_test_server *server = obj->servers + server_index; + if (config.servers[server_index].disable_udp) + { +- close (server->socket_udp); ++ xclose (server->socket_udp); + server->socket_udp = -1; + } + else if (!config.single_thread_udp) +@@ -1033,7 +1114,7 @@ resolv_test_start (struct resolv_redirect_config config) + server_thread_udp); + if (config.servers[server_index].disable_tcp) + { +- close (server->socket_tcp); ++ xclose (server->socket_tcp); + server->socket_tcp = -1; + } + else +@@ -1043,6 +1124,9 @@ resolv_test_start (struct resolv_redirect_config config) + if (config.single_thread_udp) + start_server_thread_udp_single (obj); + ++ if (config.disable_redirect) ++ return obj; ++ + int timeout = 1; + + /* Initialize libresolv. */ +@@ -1077,6 +1161,7 @@ resolv_test_start (struct resolv_redirect_config config) + } + for (int server_index = 0; server_index < config.nscount; ++server_index) + { ++ TEST_VERIFY_EXIT (obj->servers[server_index].address.sin_port != 0); + _res.nsaddr_list[server_index] = obj->servers[server_index].address; + if (test_verbose) + { +@@ -1114,7 +1199,7 @@ resolv_test_end (struct resolv_test *obj) + xsendto (sock, "", 1, 0, + (struct sockaddr *) &obj->servers[server_index].address, + sizeof (obj->servers[server_index].address)); +- close (sock); ++ xclose (sock); + } + if (!obj->config.servers[server_index].disable_tcp) + { +@@ -1122,7 +1207,7 @@ resolv_test_end (struct resolv_test *obj) + xconnect (sock, + (struct sockaddr *) &obj->servers[server_index].address, + sizeof (obj->servers[server_index].address)); +- close (sock); ++ xclose (sock); + } + } + +@@ -1137,12 +1222,12 @@ resolv_test_end (struct resolv_test *obj) + { + if (!obj->config.single_thread_udp) + xpthread_join (obj->servers[server_index].thread_udp); +- close (obj->servers[server_index].socket_udp); ++ xclose (obj->servers[server_index].socket_udp); + } + if (!obj->config.servers[server_index].disable_tcp) + { + xpthread_join (obj->servers[server_index].thread_tcp); +- close (obj->servers[server_index].socket_tcp); ++ xclose (obj->servers[server_index].socket_tcp); + } + } + +diff --git a/support/resolv_test.h b/support/resolv_test.h +index 7a9f1f7ae8..b953dc1200 100644 +--- a/support/resolv_test.h ++++ b/support/resolv_test.h +@@ -25,6 +25,16 @@ + + __BEGIN_DECLS + ++/* Information about EDNS properties of a DNS query. */ ++struct resolv_edns_info ++{ ++ bool active; ++ uint8_t extended_rcode; ++ uint8_t version; ++ uint16_t flags; ++ uint16_t payload_size; ++}; ++ + /* This struct provides context information when the response callback + specified in struct resolv_redirect_config is invoked. */ + struct resolv_response_context +@@ -33,6 +43,7 @@ struct resolv_response_context + size_t query_length; + int server_index; + bool tcp; ++ struct resolv_edns_info edns; + }; + + /* This opaque struct is used to construct responses from within the +@@ -82,6 +93,16 @@ struct resolv_redirect_config + may results in more predictable ordering of queries and + responses. */ + bool single_thread_udp; ++ ++ /* Do not rewrite the _res variable or change NSS defaults. Use ++ server_address_overrides below to tell the testing framework on ++ which addresses to create the servers. */ ++ bool disable_redirect; ++ ++ /* Use these addresses for creating the DNS servers. The array must ++ have ns_count (or resolv_max_test_servers) sockaddr * elements if ++ not NULL. */ ++ const struct sockaddr *const *server_address_overrides; + }; + + /* Configure NSS to use, nss_dns only for aplicable databases, and try +diff --git a/support/support-xstat.c b/support/support-xstat.c +new file mode 100644 +index 0000000000..86a81ec601 +--- /dev/null ++++ b/support/support-xstat.c +@@ -0,0 +1,30 @@ ++/* stat64 with error checking. ++ Copyright (C) 2017 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 ++ . */ ++ ++/* NB: Non-standard file name to avoid sysdeps override for xstat. */ ++ ++#include ++#include ++#include ++ ++void ++xstat (const char *path, struct stat64 *result) ++{ ++ if (stat64 (path, result) != 0) ++ FAIL_EXIT1 ("stat64 (\"%s\"): %m", path); ++} +diff --git a/support/support.h b/support/support.h +index 7292e2a564..4b5f04c2cc 100644 +--- a/support/support.h ++++ b/support/support.h +@@ -44,6 +44,21 @@ void set_fortify_handler (void (*handler) (int sig)); + void oom_error (const char *function, size_t size) + __attribute__ ((nonnull (1))); + ++/* Return a pointer to a memory region of SIZE bytes. The memory is ++ initialized to zero and will be shared with subprocesses (across ++ fork). The returned pointer must be freed using ++ support_shared_free; it is not compatible with the malloc ++ functions. */ ++void *support_shared_allocate (size_t size); ++ ++/* Deallocate a pointer returned by support_shared_allocate. */ ++void support_shared_free (void *); ++ ++/* Write CONTENTS to the file PATH. Create or truncate the file as ++ needed. The file mode is 0666 masked by the umask. Terminate the ++ process on error. */ ++void support_write_file_string (const char *path, const char *contents); ++ + /* Error-checking wrapper functions which terminate the process on + error. */ + +diff --git a/support/support_can_chroot.c b/support/support_can_chroot.c +new file mode 100644 +index 0000000000..0dfd2deb54 +--- /dev/null ++++ b/support/support_can_chroot.c +@@ -0,0 +1,65 @@ ++/* Return true if the process can perform a chroot operation. ++ Copyright (C) 2017 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static void ++callback (void *closure) ++{ ++ int *result = closure; ++ struct stat64 before; ++ xstat ("/dev", &before); ++ if (chroot ("/dev") != 0) ++ { ++ *result = errno; ++ return; ++ } ++ struct stat64 after; ++ xstat ("/", &after); ++ TEST_VERIFY (before.st_dev == after.st_dev); ++ TEST_VERIFY (before.st_ino == after.st_ino); ++ *result = 0; ++} ++ ++bool ++support_can_chroot (void) ++{ ++ int *result = support_shared_allocate (sizeof (*result)); ++ *result = 0; ++ support_isolate_in_subprocess (callback, result); ++ bool ok = *result == 0; ++ if (!ok) ++ { ++ static bool already_warned; ++ if (!already_warned) ++ { ++ already_warned = true; ++ errno = *result; ++ printf ("warning: this process does not support chroot: %m\n"); ++ } ++ } ++ support_shared_free (result); ++ return ok; ++} +diff --git a/support/support_capture_subprocess.c b/support/support_capture_subprocess.c +new file mode 100644 +index 0000000000..030f124252 +--- /dev/null ++++ b/support/support_capture_subprocess.c +@@ -0,0 +1,108 @@ ++/* Capture output from a subprocess. ++ Copyright (C) 2017 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 ++ . */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++static void ++transfer (const char *what, struct pollfd *pfd, struct xmemstream *stream) ++{ ++ if (pfd->revents != 0) ++ { ++ char buf[1024]; ++ ssize_t ret = TEMP_FAILURE_RETRY (read (pfd->fd, buf, sizeof (buf))); ++ if (ret < 0) ++ { ++ support_record_failure (); ++ printf ("error: reading from subprocess %s: %m", what); ++ pfd->events = 0; ++ pfd->revents = 0; ++ } ++ else if (ret == 0) ++ { ++ /* EOF reached. Stop listening. */ ++ pfd->events = 0; ++ pfd->revents = 0; ++ } ++ else ++ /* Store the data just read. */ ++ TEST_VERIFY (fwrite (buf, ret, 1, stream->out) == 1); ++ } ++} ++ ++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); ++ ++ int stdout_pipe[2]; ++ xpipe (stdout_pipe); ++ int stderr_pipe[2]; ++ xpipe (stderr_pipe); ++ ++ 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); ++ 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 }, ++ }; ++ ++ do ++ { ++ xpoll (fds, 2, -1); ++ 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); ++ return result; ++} ++ ++void ++support_capture_subprocess_free (struct support_capture_subprocess *p) ++{ ++ free (p->out.buffer); ++ free (p->err.buffer); ++} +diff --git a/support/support_capture_subprocess_check.c b/support/support_capture_subprocess_check.c +new file mode 100644 +index 0000000000..e1cf73b6a5 +--- /dev/null ++++ b/support/support_capture_subprocess_check.c +@@ -0,0 +1,67 @@ ++/* Verify capture output from a subprocess. ++ Copyright (C) 2017 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++static void ++print_context (const char *context, bool *failed) ++{ ++ if (*failed) ++ /* Do not duplicate message. */ ++ return; ++ support_record_failure (); ++ printf ("error: subprocess failed: %s\n", context); ++} ++ ++void ++support_capture_subprocess_check (struct support_capture_subprocess *proc, ++ const char *context, int status, ++ int allowed) ++{ ++ TEST_VERIFY ((allowed & sc_allow_none) ++ || (allowed & sc_allow_stdout) ++ || (allowed & sc_allow_stderr)); ++ TEST_VERIFY (!((allowed & sc_allow_none) ++ && ((allowed & sc_allow_stdout) ++ || (allowed & sc_allow_stderr)))); ++ ++ bool failed = false; ++ if (proc->status != status) ++ { ++ print_context (context, &failed); ++ printf ("error: expected exit status: %d\n", status); ++ printf ("error: actual exit status: %d\n", proc->status); ++ } ++ if (!(allowed & sc_allow_stdout) && proc->out.length != 0) ++ { ++ print_context (context, &failed); ++ printf ("error: unexpected output from subprocess\n"); ++ fwrite (proc->out.buffer, proc->out.length, 1, stdout); ++ puts ("\n"); ++ } ++ if (!(allowed & sc_allow_stderr) && proc->err.length != 0) ++ { ++ print_context (context, &failed); ++ printf ("error: unexpected error output from subprocess\n"); ++ fwrite (proc->err.buffer, proc->err.length, 1, stdout); ++ puts ("\n"); ++ } ++} +diff --git a/support/support_chroot.c b/support/support_chroot.c +new file mode 100644 +index 0000000000..f3ef551b05 +--- /dev/null ++++ b/support/support_chroot.c +@@ -0,0 +1,85 @@ ++/* Setup a chroot environment for use within tests. ++ Copyright (C) 2017 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* If CONTENTS is not NULL, write it to the file at DIRECTORY/RELPATH, ++ and store the name in *ABSPATH. If CONTENTS is NULL, store NULL in ++ *ABSPATH. */ ++static void ++write_file (const char *directory, const char *relpath, const char *contents, ++ char **abspath) ++{ ++ if (contents != NULL) ++ { ++ *abspath = xasprintf ("%s/%s", directory, relpath); ++ add_temp_file (*abspath); ++ support_write_file_string (*abspath, contents); ++ } ++ else ++ *abspath = NULL; ++} ++ ++struct support_chroot * ++support_chroot_create (struct support_chroot_configuration conf) ++{ ++ struct support_chroot *chroot = xmalloc (sizeof (*chroot)); ++ ++ chroot->path_chroot = xasprintf ("%s/tst-resolv-res_init-XXXXXX", test_dir); ++ if (mkdtemp (chroot->path_chroot) == NULL) ++ FAIL_EXIT1 ("mkdtemp (\"%s\"): %m", chroot->path_chroot); ++ add_temp_file (chroot->path_chroot); ++ ++ /* Create the /etc directory in the chroot environment. */ ++ char *path_etc = xasprintf ("%s/etc", chroot->path_chroot); ++ xmkdir (path_etc, 0777); ++ add_temp_file (path_etc); ++ ++ write_file (path_etc, "resolv.conf", conf.resolv_conf, ++ &chroot->path_resolv_conf); ++ write_file (path_etc, "hosts", conf.hosts, &chroot->path_hosts); ++ write_file (path_etc, "host.conf", conf.host_conf, &chroot->path_host_conf); ++ ++ free (path_etc); ++ ++ /* valgrind needs a temporary directory in the chroot. */ ++ { ++ char *path_tmp = xasprintf ("%s/tmp", chroot->path_chroot); ++ xmkdir (path_tmp, 0777); ++ add_temp_file (path_tmp); ++ free (path_tmp); ++ } ++ ++ return chroot; ++} ++ ++void ++support_chroot_free (struct support_chroot *chroot) ++{ ++ free (chroot->path_chroot); ++ free (chroot->path_resolv_conf); ++ free (chroot->path_hosts); ++ free (chroot->path_host_conf); ++ free (chroot); ++} +diff --git a/support/support_enter_network_namespace.c b/support/support_enter_network_namespace.c +index d2e78fe560..28b0ee29cf 100644 +--- a/support/support_enter_network_namespace.c ++++ b/support/support_enter_network_namespace.c +@@ -23,9 +23,10 @@ + #include + #include + #include ++#include ++#include + #include + #include +-#include + + static bool in_uts_namespace; + +@@ -58,7 +59,7 @@ support_enter_network_namespace (void) + req.ifr_flags |= IFF_UP | IFF_RUNNING; + TEST_VERIFY_EXIT (ioctl (fd, SIOCSIFFLAGS, &req) == 0); + } +- close (fd); ++ xclose (fd); + + return !already_up; + } +diff --git a/support/support_format_addrinfo.c b/support/support_format_addrinfo.c +index 262e0df737..eedb030591 100644 +--- a/support/support_format_addrinfo.c ++++ b/support/support_format_addrinfo.c +@@ -39,8 +39,8 @@ socket_address_length (int family) + } + + static void +-format_ai_flags (FILE *out, struct addrinfo *ai, int flag, const char *name, +- int * flags_printed) ++format_ai_flags_1 (FILE *out, struct addrinfo *ai, int flag, const char *name, ++ int * flags_printed) + { + if ((ai->ai_flags & flag) != 0) + fprintf (out, " %s", name); +@@ -48,14 +48,16 @@ format_ai_flags (FILE *out, struct addrinfo *ai, int flag, const char *name, + } + + static void +-format_ai_one (FILE *out, struct addrinfo *ai, int *flags) ++format_ai_flags (FILE *out, struct addrinfo *ai) + { +- /* ai_flags */ +- if (ai->ai_flags != *flags) ++ if (ai == NULL) ++ return; ++ ++ if (ai->ai_flags != 0) + { + fprintf (out, "flags:"); + int flags_printed = 0; +-#define FLAG(flag) format_ai_flags (out, ai, flag, #flag, &flags_printed) ++#define FLAG(flag) format_ai_flags_1 (out, ai, flag, #flag, &flags_printed) + FLAG (AI_PASSIVE); + FLAG (AI_CANONNAME); + FLAG (AI_NUMERICHOST); +@@ -72,9 +74,47 @@ format_ai_one (FILE *out, struct addrinfo *ai, int *flags) + if (remaining != 0) + fprintf (out, " %08x", remaining); + fprintf (out, "\n"); +- *flags = ai->ai_flags; + } + ++ /* Report flag mismatches within the list. */ ++ int flags = ai->ai_flags; ++ int index = 1; ++ ai = ai->ai_next; ++ while (ai != NULL) ++ { ++ if (ai->ai_flags != flags) ++ fprintf (out, "error: flags at %d: 0x%x expected, 0x%x actual\n", ++ index, flags, ai->ai_flags); ++ ai = ai->ai_next; ++ ++index; ++ } ++} ++ ++static void ++format_ai_canonname (FILE *out, struct addrinfo *ai) ++{ ++ if (ai == NULL) ++ return; ++ if (ai->ai_canonname != NULL) ++ fprintf (out, "canonname: %s\n", ai->ai_canonname); ++ ++ /* Report incorrectly set ai_canonname fields on subsequent list ++ entries. */ ++ int index = 1; ++ ai = ai->ai_next; ++ while (ai != NULL) ++ { ++ if (ai->ai_canonname != NULL) ++ fprintf (out, "error: canonname set at %d: %s\n", ++ index, ai->ai_canonname); ++ ai = ai->ai_next; ++ ++index; ++ } ++} ++ ++static void ++format_ai_one (FILE *out, struct addrinfo *ai) ++{ + { + char type_buf[32]; + const char *type_str; +@@ -156,20 +196,16 @@ format_ai_one (FILE *out, struct addrinfo *ai, int *flags) + else + fprintf (out, " %s %u\n", buf, ntohs (port)); + } +- +- /* ai_canonname */ +- if (ai->ai_canonname != NULL) +- fprintf (out, "canonname: %s\n", ai->ai_canonname); + } + + /* Format all the addresses in one address family. */ + static void +-format_ai_family (FILE *out, struct addrinfo *ai, int family, int *flags) ++format_ai_family (FILE *out, struct addrinfo *ai, int family) + { + while (ai) + { + if (ai->ai_family == family) +- format_ai_one (out, ai, flags); ++ format_ai_one (out, ai); + ai = ai->ai_next; + } + } +@@ -192,9 +228,10 @@ support_format_addrinfo (struct addrinfo *ai, int ret) + } + else + { +- int flags = 0; +- format_ai_family (mem.out, ai, AF_INET, &flags); +- format_ai_family (mem.out, ai, AF_INET6, &flags); ++ format_ai_flags (mem.out, ai); ++ format_ai_canonname (mem.out, ai); ++ format_ai_family (mem.out, ai, AF_INET); ++ format_ai_family (mem.out, ai, AF_INET6); + } + + xfclose_memstream (&mem); +diff --git a/support/support_format_dns_packet.c b/support/support_format_dns_packet.c +index 21fe7e5c8d..2992c57971 100644 +--- a/support/support_format_dns_packet.c ++++ b/support/support_format_dns_packet.c +@@ -174,7 +174,7 @@ support_format_dns_packet (const unsigned char *buffer, size_t length) + goto out; + } + /* Skip non-matching record types. */ +- if (rtype != qtype || rclass != qclass) ++ if ((rtype != qtype && rtype != T_CNAME) || rclass != qclass) + continue; + switch (rtype) + { +@@ -186,22 +186,29 @@ support_format_dns_packet (const unsigned char *buffer, size_t length) + rdata.data[2], + rdata.data[3]); + else +- fprintf (mem.out, "error: A record of size %d: %s\n", rdlen, rname.name); ++ fprintf (mem.out, "error: A record of size %d: %s\n", ++ rdlen, rname.name); + break; + case T_AAAA: + { +- char buf[100]; +- if (inet_ntop (AF_INET6, rdata.data, buf, sizeof (buf)) == NULL) +- fprintf (mem.out, "error: AAAA record decoding failed: %m\n"); ++ if (rdlen == 16) ++ { ++ char buf[100]; ++ if (inet_ntop (AF_INET6, rdata.data, buf, sizeof (buf)) == NULL) ++ fprintf (mem.out, "error: AAAA record decoding failed: %m\n"); ++ else ++ fprintf (mem.out, "address: %s\n", buf); ++ } + else +- fprintf (mem.out, "address: %s\n", buf); ++ fprintf (mem.out, "error: AAAA record of size %d: %s\n", ++ rdlen, rname.name); + } + break; + case T_CNAME: + case T_PTR: + { + struct dname name; +- if (extract_name (full, &in, &name)) ++ if (extract_name (full, &rdata, &name)) + fprintf (mem.out, "name: %s\n", name.name); + else + fprintf (mem.out, "error: malformed CNAME/PTR record\n"); +diff --git a/support/support_format_hostent.c b/support/support_format_hostent.c +index 5b5f26082e..88c85ec1f1 100644 +--- a/support/support_format_hostent.c ++++ b/support/support_format_hostent.c +@@ -19,6 +19,7 @@ + #include + + #include ++#include + #include + #include + #include +@@ -41,10 +42,15 @@ support_format_hostent (struct hostent *h) + { + if (h == NULL) + { +- char *value = support_format_herrno (h_errno); +- char *result = xasprintf ("error: %s\n", value); +- free (value); +- return result; ++ if (h_errno == NETDB_INTERNAL) ++ return xasprintf ("error: NETDB_INTERNAL (errno %d, %m)\n", errno); ++ else ++ { ++ char *value = support_format_herrno (h_errno); ++ char *result = xasprintf ("error: %s\n", value); ++ free (value); ++ return result; ++ } + } + + struct xmemstream mem; +diff --git a/support/support_isolate_in_subprocess.c b/support/support_isolate_in_subprocess.c +new file mode 100644 +index 0000000000..cf48614383 +--- /dev/null ++++ b/support/support_isolate_in_subprocess.c +@@ -0,0 +1,38 @@ ++/* Run a function in a subprocess. ++ Copyright (C) 2017 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 ++ . */ ++ ++#include ++#include ++ ++void ++support_isolate_in_subprocess (void (*callback) (void *), void *closure) ++{ ++ pid_t pid = xfork (); ++ if (pid == 0) ++ { ++ /* Child process. */ ++ callback (closure); ++ _exit (0); ++ } ++ ++ /* Parent process. */ ++ int status; ++ xwaitpid (pid, &status, 0); ++ if (status != 0) ++ FAIL_EXIT1 ("child process exited with status %d", status); ++} +diff --git a/support/support_run_diff.c b/support/support_run_diff.c +index 3085037a69..f5155de727 100644 +--- a/support/support_run_diff.c ++++ b/support/support_run_diff.c +@@ -24,8 +24,8 @@ + #include + #include + #include ++#include + #include +-#include + + static char * + write_to_temp_file (const char *prefix, const char *str) +@@ -36,7 +36,7 @@ write_to_temp_file (const char *prefix, const char *str) + TEST_VERIFY_EXIT (fd >= 0); + free (template); + xwrite (fd, str, strlen (str)); +- TEST_VERIFY_EXIT (close (fd) == 0); ++ xclose (fd); + return name; + } + +diff --git a/support/support_shared_allocate.c b/support/support_shared_allocate.c +new file mode 100644 +index 0000000000..61d088e8cf +--- /dev/null ++++ b/support/support_shared_allocate.c +@@ -0,0 +1,57 @@ ++/* Allocate a memory region shared across processes. ++ Copyright (C) 2017 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* Header for the allocation. It contains the size of the allocation ++ for subsequent unmapping. */ ++struct header ++{ ++ size_t total_size; ++ char data[] __attribute__ ((aligned (__alignof__ (max_align_t)))); ++}; ++ ++void * ++support_shared_allocate (size_t size) ++{ ++ size_t total_size = size + offsetof (struct header, data); ++ if (total_size < size) ++ { ++ errno = ENOMEM; ++ oom_error (__func__, size); ++ return NULL; ++ } ++ else ++ { ++ struct header *result = xmmap (NULL, total_size, PROT_READ | PROT_WRITE, ++ MAP_ANONYMOUS | MAP_SHARED, -1); ++ result->total_size = total_size; ++ return &result->data; ++ } ++} ++ ++void ++support_shared_free (void *data) ++{ ++ struct header *header = data - offsetof (struct header, data); ++ xmunmap (header, header->total_size); ++} +diff --git a/support/support_test_main.c b/support/support_test_main.c +index 914d64f603..3c411a467b 100644 +--- a/support/support_test_main.c ++++ b/support/support_test_main.c +@@ -211,7 +211,8 @@ support_test_main (int argc, char **argv, const struct test_config *config) + mallopt (M_PERTURB, 42); + } + +- while ((opt = getopt_long (argc, argv, "+", options, NULL)) != -1) ++ while ((opt = getopt_long (argc, argv, config->optstring, options, NULL)) ++ != -1) + switch (opt) + { + case '?': +diff --git a/support/support_test_verify_impl.c b/support/support_test_verify_impl.c +index 5bae38f8b1..55ab2111b3 100644 +--- a/support/support_test_verify_impl.c ++++ b/support/support_test_verify_impl.c +@@ -22,12 +22,16 @@ + #include + + void +-support_test_verify_impl (int status, const char *file, int line, +- const char *expr) ++support_test_verify_impl (const char *file, int line, const char *expr) + { + support_record_failure (); + printf ("error: %s:%d: not true: %s\n", file, line, expr); +- if (status >= 0) +- exit (status); ++} + ++void ++support_test_verify_exit_impl (int status, const char *file, int line, ++ const char *expr) ++{ ++ support_test_verify_impl (file, line, expr); ++ exit (status); + } +diff --git a/support/support_write_file_string.c b/support/support_write_file_string.c +new file mode 100644 +index 0000000000..48e89597f3 +--- /dev/null ++++ b/support/support_write_file_string.c +@@ -0,0 +1,39 @@ ++/* Write a string to a file. ++ Copyright (C) 2017 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++void ++support_write_file_string (const char *path, const char *contents) ++{ ++ int fd = xopen (path, O_CREAT | O_TRUNC | O_WRONLY, 0666); ++ const char *end = contents + strlen (contents); ++ for (const char *p = contents; p < end; ) ++ { ++ ssize_t ret = write (fd, p, end - p); ++ if (ret < 0) ++ FAIL_EXIT1 ("cannot write to \"%s\": %m", path); ++ if (ret == 0) ++ FAIL_EXIT1 ("zero-length write to \"%s\"", path); ++ p += ret; ++ } ++ xclose (fd); ++} +diff --git a/support/temp_file.c b/support/temp_file.c +index f06647a467..fdb2477ab9 100644 +--- a/support/temp_file.c ++++ b/support/temp_file.c +@@ -25,16 +25,17 @@ + #include + + #include +-#include + #include + #include + #include ++#include + + /* List of temporary files. */ + static struct temp_name_list + { +- struct qelem q; ++ struct temp_name_list *next; + char *name; ++ pid_t owner; + } *temp_name_list; + + /* Location of the temporary files. Set by the test skeleton via +@@ -50,10 +51,9 @@ add_temp_file (const char *name) + if (newname != NULL) + { + newp->name = newname; +- if (temp_name_list == NULL) +- temp_name_list = (struct temp_name_list *) &newp->q; +- else +- insque (newp, temp_name_list); ++ newp->next = temp_name_list; ++ newp->owner = getpid (); ++ temp_name_list = newp; + } + else + free (newp); +@@ -97,13 +97,22 @@ support_set_test_dir (const char *path) + void + support_delete_temp_files (void) + { ++ pid_t pid = getpid (); + while (temp_name_list != NULL) + { +- remove (temp_name_list->name); ++ /* Only perform the removal if the path was registed in the same ++ process, as identified by the PID. (This assumes that the ++ parent process which registered the temporary file sticks ++ around, to prevent PID reuse.) */ ++ if (temp_name_list->owner == pid) ++ { ++ if (remove (temp_name_list->name) != 0) ++ printf ("warning: could not remove temporary file: %s: %m\n", ++ temp_name_list->name); ++ } + free (temp_name_list->name); + +- struct temp_name_list *next +- = (struct temp_name_list *) temp_name_list->q.q_forw; ++ struct temp_name_list *next = temp_name_list->next; + free (temp_name_list); + temp_name_list = next; + } +@@ -116,9 +125,7 @@ support_print_temp_files (FILE *f) + { + struct temp_name_list *n; + fprintf (f, "temp_files=(\n"); +- for (n = temp_name_list; +- n != NULL; +- n = (struct temp_name_list *) n->q.q_forw) ++ for (n = temp_name_list; n != NULL; n = n->next) + fprintf (f, " '%s'\n", n->name); + fprintf (f, ")\n"); + } +diff --git a/support/test-driver.c b/support/test-driver.c +index 482066dbeb..47c387c2b4 100644 +--- a/support/test-driver.c ++++ b/support/test-driver.c +@@ -93,6 +93,10 @@ + has this type: + + void CMDLINE_PROCESS (int); ++ ++ If the program also to process custom default short command line ++ argument (similar to getopt) it must define CMDLINE_OPTSTRING ++ with the expected options (for instance "vb"). + */ + + #include +@@ -151,6 +155,11 @@ main (int argc, char **argv) + #ifdef CMDLINE_PROCESS + test_config.cmdline_function = CMDLINE_PROCESS; + #endif ++#ifdef CMDLINE_OPTSTRING ++ test_config.optstring = "+" CMDLINE_OPTSTRING; ++#else ++ test_config.optstring = "+"; ++#endif + + return support_test_main (argc, argv, &test_config); + } +diff --git a/support/test-driver.h b/support/test-driver.h +index af1971a9ca..a8fe9c3565 100644 +--- a/support/test-driver.h ++++ b/support/test-driver.h +@@ -35,6 +35,7 @@ struct test_config + int expected_status; /* Expected exit status. */ + int expected_signal; /* If non-zero, expect termination by signal. */ + char no_mallopt; /* Boolean flag to disable mallopt. */ ++ const char *optstring; /* Short command line options. */ + }; + + enum +diff --git a/support/tst-support-namespace.c b/support/tst-support-namespace.c +index a50b074f5e..dbe7cc07c8 100644 +--- a/support/tst-support-namespace.c ++++ b/support/tst-support-namespace.c +@@ -16,18 +16,98 @@ + License along with the GNU C Library; if not, see + . */ + ++#include ++#include + #include ++#include + #include ++#include ++#include ++ ++/* Check that the loopback interface provides multiple addresses which ++ can be used to run independent servers. */ ++static void ++test_localhost_bind (void) ++{ ++ printf ("info: testing loopback interface with multiple addresses\n"); ++ ++ /* Create the two server addresses. */ ++ static const struct addrinfo hints = ++ { ++ .ai_family = AF_INET, ++ .ai_socktype = SOCK_DGRAM, ++ .ai_protocol = IPPROTO_UDP, ++ }; ++ struct addrinfo *ai[3]; ++ TEST_VERIFY_EXIT (getaddrinfo ("127.0.0.1", "53", &hints, ai + 0) == 0); ++ TEST_VERIFY_EXIT (getaddrinfo ("127.0.0.2", "53", &hints, ai + 1) == 0); ++ TEST_VERIFY_EXIT (getaddrinfo ("127.0.0.3", "53", &hints, ai + 2) == 0); ++ ++ /* Create the server scokets and bind them to these addresses. */ ++ int sockets[3]; ++ for (int i = 0; i < 3; ++i) ++ { ++ sockets[i] = xsocket ++ (ai[i]->ai_family, ai[i]->ai_socktype, ai[i]->ai_protocol); ++ xbind (sockets[i], ai[i]->ai_addr, ai[i]->ai_addrlen); ++ } ++ ++ /* Send two packets to each server. */ ++ int client = xsocket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); ++ for (int i = 0; i < 3; ++i) ++ { ++ TEST_VERIFY (sendto (client, &i, sizeof (i), 0, ++ ai[i]->ai_addr, ai[i]->ai_addrlen) == sizeof (i)); ++ int j = i + 256; ++ TEST_VERIFY (sendto (client, &j, sizeof (j), 0, ++ ai[i]->ai_addr, ai[i]->ai_addrlen) == sizeof (j)); ++ } ++ ++ /* Check that the packets can be received with the expected ++ contents. Note that the receive calls interleave differently, ++ which hopefully proves that the sockets are, indeed, ++ independent. */ ++ for (int i = 0; i < 3; ++i) ++ { ++ int buf; ++ TEST_VERIFY (recv (sockets[i], &buf, sizeof (buf), 0) == sizeof (buf)); ++ TEST_VERIFY (buf == i); ++ } ++ for (int i = 0; i < 3; ++i) ++ { ++ int buf; ++ TEST_VERIFY (recv (sockets[i], &buf, sizeof (buf), 0) == sizeof (buf)); ++ TEST_VERIFY (buf == i + 256); ++ /* Check that there is no more data to receive. */ ++ TEST_VERIFY (recv (sockets[i], &buf, sizeof (buf), MSG_DONTWAIT) == -1); ++ TEST_VERIFY (errno == EWOULDBLOCK || errno == EAGAIN); ++ } ++ ++ /* Close all sockets and free the addresses. */ ++ for (int i = 0; i < 3; ++i) ++ { ++ freeaddrinfo (ai[i]); ++ xclose (sockets[i]); ++ } ++ xclose (client); ++} ++ + + static int + do_test (void) + { +- if (support_become_root ()) ++ bool root = support_become_root (); ++ if (root) + printf ("info: acquired root-like privileges\n"); +- if (support_enter_network_namespace ()) ++ bool netns = support_enter_network_namespace (); ++ if (netns) + printf ("info: entered network namespace\n"); + if (support_in_uts_namespace ()) + printf ("info: also entered UTS namespace\n"); ++ ++ if (root && netns) ++ test_localhost_bind (); ++ + return 0; + } + +diff --git a/support/tst-support_capture_subprocess.c b/support/tst-support_capture_subprocess.c +new file mode 100644 +index 0000000000..5672fba0f7 +--- /dev/null ++++ b/support/tst-support_capture_subprocess.c +@@ -0,0 +1,188 @@ ++/* Test capturing output from a subprocess. ++ Copyright (C) 2017 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Write one byte at *P to FD and advance *P. Do nothing if *P is ++ '\0'. */ ++static void ++transfer (const unsigned char **p, int fd) ++{ ++ if (**p != '\0') ++ { ++ TEST_VERIFY (write (fd, *p, 1) == 1); ++ ++*p; ++ } ++} ++ ++/* Determine the order in which stdout and stderr are written. */ ++enum write_mode { out_first, err_first, interleave, ++ write_mode_last = interleave }; ++ ++/* Describe what to write in the subprocess. */ ++struct test ++{ ++ char *out; ++ char *err; ++ enum write_mode write_mode; ++ int signal; ++ int status; ++}; ++ ++/* For use with support_capture_subprocess. */ ++static void ++callback (void *closure) ++{ ++ const struct test *test = closure; ++ bool mode_ok = false; ++ switch (test->write_mode) ++ { ++ case out_first: ++ TEST_VERIFY (fputs (test->out, stdout) >= 0); ++ TEST_VERIFY (fflush (stdout) == 0); ++ TEST_VERIFY (fputs (test->err, stderr) >= 0); ++ TEST_VERIFY (fflush (stderr) == 0); ++ mode_ok = true; ++ break; ++ case err_first: ++ TEST_VERIFY (fputs (test->err, stderr) >= 0); ++ TEST_VERIFY (fflush (stderr) == 0); ++ TEST_VERIFY (fputs (test->out, stdout) >= 0); ++ TEST_VERIFY (fflush (stdout) == 0); ++ mode_ok = true; ++ break; ++ case interleave: ++ { ++ const unsigned char *pout = (const unsigned char *) test->out; ++ const unsigned char *perr = (const unsigned char *) test->err; ++ do ++ { ++ transfer (&pout, STDOUT_FILENO); ++ transfer (&perr, STDERR_FILENO); ++ } ++ while (*pout != '\0' || *perr != '\0'); ++ } ++ mode_ok = true; ++ break; ++ } ++ TEST_VERIFY (mode_ok); ++ ++ if (test->signal != 0) ++ raise (test->signal); ++ exit (test->status); ++} ++ ++/* Create a heap-allocated random string of letters. */ ++static char * ++random_string (size_t length) ++{ ++ char *result = xmalloc (length + 1); ++ for (size_t i = 0; i < length; ++i) ++ result[i] = 'a' + (rand () % 26); ++ result[length] = '\0'; ++ return result; ++} ++ ++/* Check that the specific stream from the captured subprocess matches ++ expectations. */ ++static void ++check_stream (const char *what, const struct xmemstream *stream, ++ const char *expected) ++{ ++ if (strcmp (stream->buffer, expected) != 0) ++ { ++ support_record_failure (); ++ printf ("error: captured %s data incorrect\n" ++ " expected: %s\n" ++ " actual: %s\n", ++ what, expected, stream->buffer); ++ } ++ if (stream->length != strlen (expected)) ++ { ++ support_record_failure (); ++ printf ("error: captured %s data length incorrect\n" ++ " expected: %zu\n" ++ " actual: %zu\n", ++ what, strlen (expected), stream->length); ++ } ++} ++ ++static int ++do_test (void) ++{ ++ const int lengths[] = {0, 1, 17, 512, 20000, -1}; ++ ++ /* Test multiple combinations of support_capture_subprocess. ++ ++ length_idx_stdout: Index into the lengths array above, ++ controls how many bytes are written by the subprocess to ++ standard output. ++ length_idx_stderr: Same for standard error. ++ write_mode: How standard output and standard error writes are ++ ordered. ++ signal: Exit with no signal if zero, with SIGTERM if one. ++ status: Process exit status: 0 if zero, 3 if one. */ ++ for (int length_idx_stdout = 0; lengths[length_idx_stdout] >= 0; ++ ++length_idx_stdout) ++ for (int length_idx_stderr = 0; lengths[length_idx_stderr] >= 0; ++ ++length_idx_stderr) ++ for (int write_mode = 0; write_mode < write_mode_last; ++write_mode) ++ for (int signal = 0; signal < 2; ++signal) ++ for (int status = 0; status < 2; ++status) ++ { ++ struct test test = ++ { ++ .out = random_string (lengths[length_idx_stdout]), ++ .err = random_string (lengths[length_idx_stderr]), ++ .write_mode = write_mode, ++ .signal = signal * SIGTERM, /* 0 or SIGTERM. */ ++ .status = status * 3, /* 0 or 3. */ ++ }; ++ 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); ++ check_stream ("stdout", &result.out, test.out); ++ check_stream ("stderr", &result.err, test.err); ++ if (test.signal != 0) ++ { ++ TEST_VERIFY (WIFSIGNALED (result.status)); ++ TEST_VERIFY (WTERMSIG (result.status) == test.signal); ++ } ++ else ++ { ++ TEST_VERIFY (WIFEXITED (result.status)); ++ TEST_VERIFY (WEXITSTATUS (result.status) == test.status); ++ } ++ support_capture_subprocess_free (&result); ++ free (test.out); ++ free (test.err); ++ } ++ return 0; ++} ++ ++#include +diff --git a/support/tst-support_format_dns_packet.c b/support/tst-support_format_dns_packet.c +new file mode 100644 +index 0000000000..9c8589c09c +--- /dev/null ++++ b/support/tst-support_format_dns_packet.c +@@ -0,0 +1,101 @@ ++/* Tests for the support_format_dns_packet function. ++ Copyright (C) 2016-2017 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 ++ . */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++static void ++check_packet (const void *buffer, size_t length, ++ const char *name, const char *expected) ++{ ++ char *actual = support_format_dns_packet (buffer, length); ++ if (strcmp (actual, expected) != 0) ++ { ++ support_record_failure (); ++ printf ("error: formatted packet does not match: %s\n", name); ++ support_run_diff ("expected", expected, ++ "actual", actual); ++ } ++ free (actual); ++} ++ ++static void ++test_aaaa_length (void) ++{ ++ static const char packet[] = ++ /* Header: Response with two records. */ ++ "\x12\x34\x80\x00\x00\x01\x00\x02\x00\x00\x00\x00" ++ /* Question section. www.example/IN/AAAA. */ ++ "\x03www\x07""example\x00\x00\x1c\x00\x01" ++ /* Answer section. www.example AAAA [corrupted]. */ ++ "\xc0\x0c" ++ "\x00\x1c\x00\x01\x00\x00\x00\x00\x00\x10" ++ "\x20\x01\x0d\xb8\x05\x06\x07\x08" ++ "\x11\x12\x13\x14\x15\x16\x17\x18" ++ /* www.example AAAA [corrupted]. */ ++ "\xc0\x0c" ++ "\x00\x1c\x00\x01\x00\x00\x00\x00\x00\x11" ++ "\x01\x02\x03\x04\x05\x06\x07\x08" ++ "\x11\x12\x13\x14\x15\x16\x17\x18" "\xff"; ++ check_packet (packet, sizeof (packet) - 1, __func__, ++ "name: www.example\n" ++ "address: 2001:db8:506:708:1112:1314:1516:1718\n" ++ "error: AAAA record of size 17: www.example\n"); ++} ++ ++static void ++test_multiple_cnames (void) ++{ ++ static const char packet[] = ++ /* Header: Response with three records. */ ++ "\x12\x34\x80\x00\x00\x01\x00\x03\x00\x00\x00\x00" ++ /* Question section. www.example/IN/A. */ ++ "\x03www\x07""example\x00\x00\x01\x00\x01" ++ /* Answer section. www.example CNAME www1.example. */ ++ "\xc0\x0c" ++ "\x00\x05\x00\x01\x00\x00\x00\x00\x00\x07" ++ "\x04www1\xc0\x10" ++ /* www1 CNAME www2. */ ++ "\x04www1\xc0\x10" ++ "\x00\x05\x00\x01\x00\x00\x00\x00\x00\x07" ++ "\x04www2\xc0\x10" ++ /* www2 A 192.0.2.1. */ ++ "\x04www2\xc0\x10" ++ "\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04" ++ "\xc0\x00\x02\x01"; ++ check_packet (packet, sizeof (packet) - 1, __func__, ++ "name: www.example\n" ++ "name: www1.example\n" ++ "name: www2.example\n" ++ "address: 192.0.2.1\n"); ++} ++ ++static int ++do_test (void) ++{ ++ test_aaaa_length (); ++ test_multiple_cnames (); ++ return 0; ++} ++ ++#include +diff --git a/support/tst-support_record_failure-2.sh b/support/tst-support_record_failure-2.sh +index 175137780a..2c9372cc29 100644 +--- a/support/tst-support_record_failure-2.sh ++++ b/support/tst-support_record_failure-2.sh +@@ -37,7 +37,7 @@ run_test () { + set -e + echo " exit status: $status" + if test "$output" != "$expected_output" ; then +- echo "error: unexpected ouput: $output" ++ echo "error: unexpected output: $output" + exit 1 + fi + if test "$status" -ne "$expected_status" ; then +@@ -52,9 +52,9 @@ different_status () { + run_test 1 "error: 1 test failures" $direct --status=1 + run_test 2 "error: 1 test failures" $direct --status=2 + run_test 1 "error: 1 test failures" $direct --status=77 +- run_test 2 "error: tst-support_record_failure.c:108: not true: false ++ run_test 2 "error: tst-support_record_failure.c:109: not true: false + error: 1 test failures" $direct --test-verify +- run_test 2 "error: tst-support_record_failure.c:108: not true: false ++ run_test 2 "error: tst-support_record_failure.c:109: not true: false + info: execution passed failed TEST_VERIFY + error: 1 test failures" $direct --test-verify --verbose + } +@@ -62,8 +62,8 @@ error: 1 test failures" $direct --test-verify --verbose + different_status + different_status --direct + +-run_test 1 "error: tst-support_record_failure.c:115: not true: false ++run_test 1 "error: tst-support_record_failure.c:116: not true: false + error: 1 test failures" --test-verify-exit + # --direct does not print the summary error message if exit is called. +-run_test 1 "error: tst-support_record_failure.c:115: not true: false" \ ++run_test 1 "error: tst-support_record_failure.c:116: not true: false" \ + --direct --test-verify-exit +diff --git a/support/tst-support_record_failure.c b/support/tst-support_record_failure.c +index 62d8e1f057..e739e739c3 100644 +--- a/support/tst-support_record_failure.c ++++ b/support/tst-support_record_failure.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + + static int exit_status_with_failure = -1; + static bool test_verify; +diff --git a/support/xaccept4.c b/support/xaccept4.c +new file mode 100644 +index 0000000000..67dd95e9fb +--- /dev/null ++++ b/support/xaccept4.c +@@ -0,0 +1,32 @@ ++/* accept4 with error checking. ++ Copyright (C) 2017 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 ++ . */ ++ ++#include ++ ++#include ++#include ++#include ++ ++int ++xaccept4 (int fd, struct sockaddr *sa, socklen_t *salen, int flags) ++{ ++ int clientfd = accept4 (fd, sa, salen, flags); ++ if (clientfd < 0) ++ FAIL_EXIT1 ("accept4 (%d, 0x%x): %m", fd, flags); ++ return clientfd; ++} +diff --git a/support/xchroot.c b/support/xchroot.c +new file mode 100644 +index 0000000000..abcc299e00 +--- /dev/null ++++ b/support/xchroot.c +@@ -0,0 +1,28 @@ ++/* chroot with error checking. ++ Copyright (C) 2017 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 ++ . */ ++ ++#include ++#include ++#include ++ ++void ++xchroot (const char *path) ++{ ++ if (chroot (path) != 0) ++ FAIL_EXIT1 ("chroot (\"%s\"): %m", path); ++} +diff --git a/support/xclose.c b/support/xclose.c +new file mode 100644 +index 0000000000..c931e08421 +--- /dev/null ++++ b/support/xclose.c +@@ -0,0 +1,28 @@ ++/* close with error checking. ++ Copyright (C) 2017 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 ++ . */ ++ ++#include ++#include ++#include ++ ++void ++xclose (int fd) ++{ ++ if (close (fd) < 0 && errno != EINTR) ++ FAIL_EXIT1 ("close of descriptor %d failed: %m", fd); ++} +diff --git a/support/xdlfcn.c b/support/xdlfcn.c +new file mode 100644 +index 0000000000..6e3979983d +--- /dev/null ++++ b/support/xdlfcn.c +@@ -0,0 +1,58 @@ ++/* Support functionality for using dlopen/dlclose/dlsym. ++ Copyright (C) 2017 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 ++ . */ ++ ++#include ++#include ++ ++void * ++xdlopen (const char *filename, int flags) ++{ ++ void *dso = dlopen (filename, flags); ++ ++ if (dso == NULL) ++ FAIL_EXIT1 ("error: dlopen: %s\n", dlerror ()); ++ ++ /* Clear any errors. */ ++ dlerror (); ++ ++ return dso; ++} ++ ++void * ++xdlsym (void *handle, const char *symbol) ++{ ++ void *sym = dlsym (handle, symbol); ++ ++ if (sym == NULL) ++ FAIL_EXIT1 ("error: dlsym: %s\n", dlerror ()); ++ ++ /* Clear any errors. */ ++ dlerror (); ++ ++ return sym; ++} ++ ++void ++xdlclose (void *handle) ++{ ++ if (dlclose (handle) != 0) ++ FAIL_EXIT1 ("error: dlclose: %s\n", dlerror ()); ++ ++ /* Clear any errors. */ ++ dlerror (); ++} +diff --git a/support/xdlfcn.h b/support/xdlfcn.h +new file mode 100644 +index 0000000000..9bdcb38d3e +--- /dev/null ++++ b/support/xdlfcn.h +@@ -0,0 +1,34 @@ ++/* Support functionality for using dlopen/dlclose/dlsym. ++ Copyright (C) 2017 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 ++ . */ ++ ++#ifndef SUPPORT_DLOPEN_H ++#define SUPPORT_DLOPEN_H ++ ++#include ++ ++__BEGIN_DECLS ++ ++/* Each of these terminates process on failure with relevant error message. */ ++void *xdlopen (const char *filename, int flags); ++void *xdlsym (void *handle, const char *symbol); ++void xdlclose (void *handle); ++ ++ ++__END_DECLS ++ ++#endif /* SUPPORT_DLOPEN_H */ +diff --git a/support/xdup2.c b/support/xdup2.c +new file mode 100644 +index 0000000000..dc08c94518 +--- /dev/null ++++ b/support/xdup2.c +@@ -0,0 +1,28 @@ ++/* dup2 with error checking. ++ Copyright (C) 2017 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 ++ . */ ++ ++#include ++ ++#include ++ ++void ++xdup2 (int from, int to) ++{ ++ if (dup2 (from, to) < 0) ++ FAIL_EXIT1 ("dup2 (%d, %d): %m", from, to); ++} +diff --git a/support/xmkdir.c b/support/xmkdir.c +new file mode 100644 +index 0000000000..ea17d49391 +--- /dev/null ++++ b/support/xmkdir.c +@@ -0,0 +1,28 @@ ++/* mkdir with error checking. ++ Copyright (C) 2017 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 ++ . */ ++ ++#include ++#include ++#include ++ ++void ++xmkdir (const char *path, mode_t mode) ++{ ++ if (mkdir (path, mode) != 0) ++ FAIL_EXIT1 ("mkdir (\"%s\", 0%o): %m", path, mode); ++} +diff --git a/support/xmprotect.c b/support/xmprotect.c +new file mode 100644 +index 0000000000..9410251c32 +--- /dev/null ++++ b/support/xmprotect.c +@@ -0,0 +1,28 @@ ++/* mprotect with error checking. ++ Copyright (C) 2017 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 ++ . */ ++ ++#include ++#include ++#include ++ ++void ++xmprotect (void *addr, size_t length, int prot) ++{ ++ if (mprotect (addr, length, prot) != 0) ++ FAIL_EXIT1 ("mprotect (%p, %zu, 0x%x): %m", addr, length, prot); ++} +diff --git a/support/xopen.c b/support/xopen.c +new file mode 100644 +index 0000000000..7f033a03a7 +--- /dev/null ++++ b/support/xopen.c +@@ -0,0 +1,30 @@ ++/* open64 with error checking. ++ Copyright (C) 2017 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 ++ . */ ++ ++#include ++#include ++#include ++ ++int ++xopen (const char *path, int flags, mode_t mode) ++{ ++ int ret = open64 (path, flags, mode); ++ if (ret < 0) ++ FAIL_EXIT1 ("open64 (\"%s\", 0x%x, 0%o): %m", path, flags, mode); ++ return ret; ++} +diff --git a/support/xpipe.c b/support/xpipe.c +new file mode 100644 +index 0000000000..89a64a55c1 +--- /dev/null ++++ b/support/xpipe.c +@@ -0,0 +1,28 @@ ++/* pipe with error checking. ++ Copyright (C) 2017 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 ++ . */ ++ ++#include ++ ++#include ++ ++void ++xpipe (int fds[2]) ++{ ++ if (pipe (fds) < 0) ++ FAIL_EXIT1 ("pipe: %m"); ++} +diff --git a/support/xpthread_attr_setguardsize.c b/support/xpthread_attr_setguardsize.c +new file mode 100644 +index 0000000000..35fed5d9ec +--- /dev/null ++++ b/support/xpthread_attr_setguardsize.c +@@ -0,0 +1,26 @@ ++/* pthread_attr_setguardsize with error checking. ++ Copyright (C) 2017 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 ++ . */ ++ ++#include ++ ++void ++xpthread_attr_setguardsize (pthread_attr_t *attr, size_t guardsize) ++{ ++ xpthread_check_return ("pthread_attr_setguardize", ++ pthread_attr_setguardsize (attr, guardsize)); ++} +diff --git a/support/xpthread_rwlock_init.c b/support/xpthread_rwlock_init.c +new file mode 100644 +index 0000000000..824288c90e +--- /dev/null ++++ b/support/xpthread_rwlock_init.c +@@ -0,0 +1,27 @@ ++/* pthread_rwlock_init with error checking. ++ Copyright (C) 2017 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 ++ . */ ++ ++#include ++ ++void ++xpthread_rwlock_init (pthread_rwlock_t *rwlock, ++ const pthread_rwlockattr_t *attr) ++{ ++ xpthread_check_return ("pthread_rwlock_init", ++ pthread_rwlock_init (rwlock, attr)); ++} +diff --git a/support/xpthread_rwlock_rdlock.c b/support/xpthread_rwlock_rdlock.c +new file mode 100644 +index 0000000000..96330a5637 +--- /dev/null ++++ b/support/xpthread_rwlock_rdlock.c +@@ -0,0 +1,26 @@ ++/* pthread_rwlock_rdlock with error checking. ++ Copyright (C) 2017 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 ++ . */ ++ ++#include ++ ++void ++xpthread_rwlock_rdlock (pthread_rwlock_t *rwlock) ++{ ++ xpthread_check_return ("pthread_rwlock_rdlock", ++ pthread_rwlock_rdlock (rwlock)); ++} +diff --git a/support/xpthread_rwlock_unlock.c b/support/xpthread_rwlock_unlock.c +new file mode 100644 +index 0000000000..eaa136b3ec +--- /dev/null ++++ b/support/xpthread_rwlock_unlock.c +@@ -0,0 +1,26 @@ ++/* pthread_rwlock_unlock with error checking. ++ Copyright (C) 2017 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 ++ . */ ++ ++#include ++ ++void ++xpthread_rwlock_unlock (pthread_rwlock_t *rwlock) ++{ ++ xpthread_check_return ("pthread_rwlock_unlock", ++ pthread_rwlock_unlock (rwlock)); ++} +diff --git a/support/xpthread_rwlock_wrlock.c b/support/xpthread_rwlock_wrlock.c +new file mode 100644 +index 0000000000..8d25d5b818 +--- /dev/null ++++ b/support/xpthread_rwlock_wrlock.c +@@ -0,0 +1,26 @@ ++/* pthread_rwlock_wrlock with error checking. ++ Copyright (C) 2017 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 ++ . */ ++ ++#include ++ ++void ++xpthread_rwlock_wrlock (pthread_rwlock_t *rwlock) ++{ ++ xpthread_check_return ("pthread_rwlock_wrlock", ++ pthread_rwlock_wrlock (rwlock)); ++} +diff --git a/support/xpthread_rwlockattr_init.c b/support/xpthread_rwlockattr_init.c +new file mode 100644 +index 0000000000..48baf247f3 +--- /dev/null ++++ b/support/xpthread_rwlockattr_init.c +@@ -0,0 +1,26 @@ ++/* pthread_rwlockattr_init with error checking. ++ Copyright (C) 2017 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 ++ . */ ++ ++#include ++ ++void ++xpthread_rwlockattr_init (pthread_rwlockattr_t *attr) ++{ ++ xpthread_check_return ("pthread_rwlockattr_init", ++ pthread_rwlockattr_init (attr)); ++} +diff --git a/support/xpthread_rwlockattr_setkind_np.c b/support/xpthread_rwlockattr_setkind_np.c +new file mode 100644 +index 0000000000..958aace9f6 +--- /dev/null ++++ b/support/xpthread_rwlockattr_setkind_np.c +@@ -0,0 +1,27 @@ ++/* pthread_rwlockattr_setkind_np with error checking. ++ Copyright (C) 2017 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 ++ . */ ++ ++#include ++ ++void ++xpthread_rwlockattr_setkind_np (pthread_rwlockattr_t *attr, ++ int pref) ++{ ++ xpthread_check_return ("pthread_rwlockattr_setkind_np", ++ pthread_rwlockattr_setkind_np (attr, pref)); ++} +diff --git a/support/xsocket.h b/support/xsocket.h +index 0dbf13ace9..d6724948d8 100644 +--- a/support/xsocket.h ++++ b/support/xsocket.h +@@ -30,6 +30,7 @@ void xconnect (int, const struct sockaddr *, socklen_t); + void xbind (int, const struct sockaddr *, socklen_t); + void xlisten (int, int); + int xaccept (int, struct sockaddr *, socklen_t *); ++int xaccept4 (int, struct sockaddr *, socklen_t *, int); + void xsendto (int, const void *, size_t, int, + const struct sockaddr *, socklen_t); + size_t xrecvfrom (int, void *, size_t, int, struct sockaddr *, socklen_t *); +diff --git a/support/xthread.h b/support/xthread.h +index 6dd7e709be..472763ebe8 100644 +--- a/support/xthread.h ++++ b/support/xthread.h +@@ -67,11 +67,21 @@ void xpthread_attr_setdetachstate (pthread_attr_t *attr, + int detachstate); + void xpthread_attr_setstacksize (pthread_attr_t *attr, + size_t stacksize); ++void xpthread_attr_setguardsize (pthread_attr_t *attr, ++ size_t guardsize); + + /* This function returns non-zero if pthread_barrier_wait returned + PTHREAD_BARRIER_SERIAL_THREAD. */ + int xpthread_barrier_wait (pthread_barrier_t *barrier); + ++void xpthread_rwlock_init (pthread_rwlock_t *rwlock, ++ const pthread_rwlockattr_t *attr); ++void xpthread_rwlockattr_init (pthread_rwlockattr_t *attr); ++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); ++ + __END_DECLS + + #endif /* SUPPORT_THREAD_H */ +diff --git a/support/xunistd.h b/support/xunistd.h +index a83b1f4541..c947bfd8fb 100644 +--- a/support/xunistd.h ++++ b/support/xunistd.h +@@ -22,20 +22,33 @@ + #ifndef SUPPORT_XUNISTD_H + #define SUPPORT_XUNISTD_H + +-#include + #include ++#include ++#include + + __BEGIN_DECLS + ++struct stat64; ++ + pid_t xfork (void); + pid_t xwaitpid (pid_t, int *status, int flags); ++void xpipe (int[2]); ++void xdup2 (int, int); ++int xopen (const char *path, int flags, mode_t); ++void xstat (const char *path, struct stat64 *); ++void xmkdir (const char *path, mode_t); ++void xchroot (const char *path); ++ ++/* Close the file descriptor. Ignore EINTR errors, but terminate the ++ process on other errors. */ ++void xclose (int); + + /* Write the buffer. Retry on short writes. */ + void xwrite (int, const void *, size_t); + + /* Invoke mmap with a zero file offset. */ + void *xmmap (void *addr, size_t length, int prot, int flags, int fd); +- ++void xmprotect (void *addr, size_t length, int prot); + void xmunmap (void *addr, size_t length); + + __END_DECLS +diff --git a/sysdeps/aarch64/dl-machine.h b/sysdeps/aarch64/dl-machine.h +index 84b8aecfb8..6067a1d8a0 100644 +--- a/sysdeps/aarch64/dl-machine.h ++++ b/sysdeps/aarch64/dl-machine.h +@@ -193,8 +193,8 @@ _dl_start_user: \n\ + cmp " PTR "0, #0 \n\ + bne 1b \n\ + // Update _dl_argv \n\ +- adrp x3, _dl_argv \n\ +- str " PTR "2, [x3, #:lo12:_dl_argv] \n\ ++ adrp x3, __GI__dl_argv \n\ ++ str " PTR "2, [x3, #:lo12:__GI__dl_argv] \n\ + .L_done_stack_adjust: \n\ + // compute envp \n\ + add " PTR "3, " PTR "2, " PTR "1, lsl #" PTR_SIZE_LOG " \n\ +diff --git a/sysdeps/generic/unsecvars.h b/sysdeps/generic/unsecvars.h +index a74083786e..5ea8a4a259 100644 +--- a/sysdeps/generic/unsecvars.h ++++ b/sysdeps/generic/unsecvars.h +@@ -16,6 +16,7 @@ + "LD_DEBUG\0" \ + "LD_DEBUG_OUTPUT\0" \ + "LD_DYNAMIC_WEAK\0" \ ++ "LD_HWCAP_MASK\0" \ + "LD_LIBRARY_PATH\0" \ + "LD_ORIGIN_PATH\0" \ + "LD_PRELOAD\0" \ +diff --git a/sysdeps/gnu/glob64.c b/sysdeps/gnu/glob64.c +index d1e4e6f0d5..52e97e2f6a 100644 +--- a/sysdeps/gnu/glob64.c ++++ b/sysdeps/gnu/glob64.c +@@ -15,11 +15,8 @@ + #undef __stat + #define __stat(file, buf) __xstat64 (_STAT_VER, file, buf) + +-#define NO_GLOB_PATTERN_P 1 +- + #define COMPILE_GLOB64 1 + + #include + + libc_hidden_def (glob64) +-libc_hidden_def (globfree64) +diff --git a/sysdeps/gnu/globfree64.c b/sysdeps/gnu/globfree64.c +new file mode 100644 +index 0000000000..f092d0bf8b +--- /dev/null ++++ b/sysdeps/gnu/globfree64.c +@@ -0,0 +1,10 @@ ++#include ++#include ++#include ++ ++#define glob_t glob64_t ++#define globfree(pglob) globfree64 (pglob) ++ ++#include ++ ++libc_hidden_def (globfree64) +diff --git a/sysdeps/hppa/__longjmp.c b/sysdeps/hppa/__longjmp.c +index a7eefc7ad6..2fedb1d738 100644 +--- a/sysdeps/hppa/__longjmp.c ++++ b/sysdeps/hppa/__longjmp.c +@@ -24,15 +24,15 @@ + void + __longjmp (__jmp_buf env, int val) + { ++#ifdef CHECK_SP ++ CHECK_SP (env[0].__jmp_buf.__sp); ++#endif ++ + /* We must use one of the non-callee saves registers + for env. */ + register unsigned long r26 asm ("r26") = (unsigned long)&env[0]; + register unsigned long r25 asm ("r25") = (unsigned long)(val == 0 ? 1 : val); + +-#ifdef CHECK_SP +- CHECK_SP (env[0].__jmp_buf.__sp); +-#endif +- + asm volatile( + /* Set return value. */ + "copy %0, %%r28\n\t" +@@ -79,6 +79,7 @@ __longjmp (__jmp_buf env, int val) + : /* No outputs. */ + : "r" (r25), "r" (r26) + : /* No point in clobbers. */ ); ++ + /* Avoid `volatile function does return' warnings. */ + for (;;); + } +diff --git a/sysdeps/hppa/dl-fptr.c b/sysdeps/hppa/dl-fptr.c +index 83bdb91202..f74abc02c2 100644 +--- a/sysdeps/hppa/dl-fptr.c ++++ b/sysdeps/hppa/dl-fptr.c +@@ -181,24 +181,29 @@ make_fdesc (ElfW(Addr) ip, ElfW(Addr) gp) + static inline ElfW(Addr) * __attribute__ ((always_inline)) + make_fptr_table (struct link_map *map) + { +- const ElfW(Sym) *symtab +- = (const void *) D_PTR (map, l_info[DT_SYMTAB]); ++ const ElfW(Sym) *symtab = (const void *) D_PTR (map, l_info[DT_SYMTAB]); + const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]); + ElfW(Addr) *fptr_table; + size_t size; + size_t len; ++ const ElfW(Sym) *symtabend; + +- /* XXX Apparently the only way to find out the size of the dynamic +- symbol section is to assume that the string table follows right +- afterwards... */ +- len = ((strtab - (char *) symtab) ++ /* Determine the end of the dynamic symbol table using the hash. */ ++ if (map->l_info[DT_HASH] != NULL) ++ symtabend = (symtab + ((Elf_Symndx *) D_PTR (map, l_info[DT_HASH]))[1]); ++ else ++ /* There is no direct way to determine the number of symbols in the ++ dynamic symbol table and no hash table is present. The ELF ++ binary is ill-formed but what shall we do? Use the beginning of ++ the string table which generally follows the symbol table. */ ++ symtabend = (const ElfW(Sym) *) strtab; ++ ++ len = (((char *) symtabend - (char *) symtab) + / map->l_info[DT_SYMENT]->d_un.d_val); +- size = ((len * sizeof (fptr_table[0]) + GLRO(dl_pagesize) - 1) +- & -GLRO(dl_pagesize)); +- /* XXX We don't support here in the moment systems without MAP_ANON. +- There probably are none for IA-64. In case this is proven wrong +- we will have to open /dev/null here and use the file descriptor +- instead of the hard-coded -1. */ ++ size = ALIGN_UP (len * sizeof (fptr_table[0]), GLRO(dl_pagesize)); ++ ++ /* We don't support systems without MAP_ANON. We avoid using malloc ++ because this might get called before malloc is setup. */ + fptr_table = __mmap (NULL, size, + PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, + -1, 0); +@@ -331,22 +336,45 @@ elf_machine_resolve (void) + return addr; + } + ++static inline int ++_dl_read_access_allowed (unsigned int *addr) ++{ ++ int result; ++ ++ asm ("proberi (%1),3,%0" : "=r" (result) : "r" (addr) : ); ++ ++ return result; ++} ++ + ElfW(Addr) + _dl_lookup_address (const void *address) + { + ElfW(Addr) addr = (ElfW(Addr)) address; + unsigned int *desc, *gptr; + +- /* Check for special cases. */ +- if ((int) addr == -1 +- || (unsigned int) addr < 4096 +- || !((unsigned int) addr & 2)) ++ /* Return ADDR if the least-significant two bits of ADDR are not consistent ++ with ADDR being a linker defined function pointer. The normal value for ++ a code address in a backtrace is 3. */ ++ if (((unsigned int) addr & 3) != 2) ++ return addr; ++ ++ /* Handle special case where ADDR points to page 0. */ ++ if ((unsigned int) addr < 4096) + return addr; + + /* Clear least-significant two bits from descriptor address. */ + desc = (unsigned int *) ((unsigned int) addr & ~3); ++ if (!_dl_read_access_allowed (desc)) ++ return addr; + +- /* Check if descriptor requires resolution. The following trampoline is ++ /* Load first word of candidate descriptor. It should be a pointer ++ with word alignment and point to memory that can be read. */ ++ gptr = (unsigned int *) desc[0]; ++ if (((unsigned int) gptr & 3) != 0 ++ || !_dl_read_access_allowed (gptr)) ++ return addr; ++ ++ /* See if descriptor requires resolution. The following trampoline is + used in each global offset table for function resolution: + + ldw 0(r20),r22 +@@ -358,7 +386,6 @@ _dl_lookup_address (const void *address) + .word "_dl_runtime_resolve ltp" + got: .word _DYNAMIC + .word "struct link map address" */ +- gptr = (unsigned int *) desc[0]; + if (gptr[0] == 0xea9f1fdd /* b,l .-12,r20 */ + && gptr[1] == 0xd6801c1e /* depwi 0,31,2,r20 */ + && (ElfW(Addr)) gptr[2] == elf_machine_resolve ()) +diff --git a/sysdeps/hppa/dl-machine.h b/sysdeps/hppa/dl-machine.h +index 339c7bb771..787b95f502 100644 +--- a/sysdeps/hppa/dl-machine.h ++++ b/sysdeps/hppa/dl-machine.h +@@ -302,6 +302,10 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) + #define ARCH_LA_PLTENTER hppa_gnu_pltenter + #define ARCH_LA_PLTEXIT hppa_gnu_pltexit + ++/* Adjust DL_STACK_END to get value we want in __libc_stack_end. */ ++#define DL_STACK_END(cookie) \ ++ ((void *) (((long) (cookie)) + 0x160)) ++ + /* Initial entry point code for the dynamic linker. + The C function `_dl_start' is the real entry point; + its return value is the user program's entry point. */ +@@ -401,11 +405,6 @@ asm ( \ + /* Save the entry point in %r3. */ \ + " copy %ret0,%r3\n" \ + \ +- /* Remember the lowest stack address. */ \ +-" addil LT'__libc_stack_end,%r19\n" \ +-" ldw RT'__libc_stack_end(%r1),%r20\n" \ +-" stw %sp,0(%r20)\n" \ +- \ + /* See if we were called as a command with the executable file \ + name as an extra leading argument. */ \ + " addil LT'_dl_skip_args,%r19\n" \ +diff --git a/sysdeps/hppa/dl-trampoline.S b/sysdeps/hppa/dl-trampoline.S +index 856339bffe..3165c6f0e2 100644 +--- a/sysdeps/hppa/dl-trampoline.S ++++ b/sysdeps/hppa/dl-trampoline.S +@@ -82,6 +82,21 @@ _dl_runtime_resolve: + bl _dl_fixup,%rp + copy %r21,%r19 /* set fixup func ltp */ + ++ /* While the linker will set a function pointer to NULL when it ++ encounters an undefined weak function, we need to dynamically ++ detect removed weak functions. The issue arises because a weak ++ __gmon_start__ function was added to shared executables to work ++ around issues in _init that are now resolved. The presence of ++ __gmon_start__ in every shared library breaks the linker ++ `--as-needed' option. This __gmon_start__ function does nothing ++ but removal is tricky. Depending on the binding, removal can ++ cause an application using it to fault. The call to _dl_fixup ++ returns NULL when a function isn't resolved. In order to help ++ with __gmon_start__ removal, we return directly to the caller ++ when _dl_fixup returns NULL. This check could be removed when ++ BZ 19170 is fixed. */ ++ comib,= 0,%r28,1f ++ + /* Load up the returned func descriptor */ + copy %r28, %r22 + copy %r29, %r19 +@@ -107,6 +122,13 @@ _dl_runtime_resolve: + /* Jump to new function, but return to previous function */ + bv %r0(%r22) + ldw -20(%sp),%rp ++ ++1: ++ /* Return to previous function */ ++ ldw -148(%sp),%rp ++ bv %r0(%rp) ++ ldo -128(%sp),%sp ++ + .EXIT + .PROCEND + cfi_endproc +diff --git a/sysdeps/hppa/math-tests.h b/sysdeps/hppa/math-tests.h +new file mode 100644 +index 0000000000..bb205907ad +--- /dev/null ++++ b/sysdeps/hppa/math-tests.h +@@ -0,0 +1,22 @@ ++/* Configuration for math tests. hppa version. ++ Copyright (C) 2017 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 ++ . */ ++ ++/* SNaN tests do not preserve payloads. */ ++#define SNAN_TESTS_PRESERVE_PAYLOAD 0 ++ ++#include_next +diff --git a/sysdeps/hppa/nptl/bits/pthreadtypes.h b/sysdeps/hppa/nptl/bits/pthreadtypes.h +index e37111a2f3..579047b732 100644 +--- a/sysdeps/hppa/nptl/bits/pthreadtypes.h ++++ b/sysdeps/hppa/nptl/bits/pthreadtypes.h +@@ -106,36 +106,34 @@ typedef union + + /* Data structure for conditional variable handling. The structure of + the attribute type is not exposed on purpose. However, this structure +- is exposed via PTHREAD_COND_INITIALIZER, and because of this, the +- Linuxthreads version sets the first four ints to one. In the NPTL +- version we must check, in every function using pthread_cond_t, +- for the static Linuxthreads initializer and clear the appropriate +- words. */ ++ is exposed via PTHREAD_COND_INITIALIZER. Support for Linuxthreads has ++ been dropped but we still need to retain the alignment of the original ++ lock field from Linuxthreads. */ + typedef union + { + struct + { +- /* In the old Linuxthreads pthread_cond_t, this is the +- start of the 4-word lock structure, the next four words +- are set all to 1 by the Linuxthreads +- PTHREAD_COND_INITIALIZER. */ +- int __lock __attribute__ ((__aligned__(16))); +- /* Tracks the initialization of this structure: +- 0 initialized with NPTL PTHREAD_COND_INITIALIZER. +- 1 initialized with Linuxthreads PTHREAD_COND_INITIALIZER. +- 2 initialization in progress. */ +- int __initializer; +- unsigned int __futex; +- void *__mutex; +- /* In the old Linuxthreads this would have been the start +- of the pthread_fastlock status word. */ +- __extension__ unsigned long long int __total_seq; +- __extension__ unsigned long long int __wakeup_seq; +- __extension__ unsigned long long int __woken_seq; +- unsigned int __nwaiters; +- unsigned int __broadcast_seq; +- /* The NPTL pthread_cond_t is exactly the same size as +- the Linuxthreads version, there are no words to spare. */ ++ __extension__ union ++ { ++ __extension__ unsigned long long int __wseq; ++ struct { ++ unsigned int __low; ++ unsigned int __high; ++ } __wseq32; ++ }; ++ __extension__ union ++ { ++ __extension__ unsigned long long int __g1_start; ++ struct { ++ unsigned int __low; ++ unsigned int __high; ++ } __g1_start32; ++ }; ++ unsigned int __g_refs[2] __attribute__ ((__aligned__(16))); ++ unsigned int __g_size[2]; ++ unsigned int __g1_orig_size; ++ unsigned int __wrefs; ++ unsigned int __g_signals[2]; + } __data; + char __size[__SIZEOF_PTHREAD_COND_T]; + __extension__ long long int __align; +diff --git a/sysdeps/i386/i686/fpu/multiarch/libm-test-ulps b/sysdeps/i386/i686/fpu/multiarch/libm-test-ulps +index cb82d3ee36..275dbbe804 100644 +--- a/sysdeps/i386/i686/fpu/multiarch/libm-test-ulps ++++ b/sysdeps/i386/i686/fpu/multiarch/libm-test-ulps +@@ -42,7 +42,7 @@ ldouble: 4 + Function: "acosh_upward": + double: 1 + idouble: 1 +-ildouble: 4 ++ildouble: 5 + ldouble: 3 + + Function: "asin": +@@ -900,8 +900,8 @@ double: 3 + float: 3 + idouble: 3 + ifloat: 3 +-ildouble: 7 +-ldouble: 7 ++ildouble: 8 ++ldouble: 8 + + Function: Imaginary part of "clog10_upward": + double: 1 +@@ -1591,8 +1591,8 @@ double: 3 + float: 4 + idouble: 3 + ifloat: 4 +-ildouble: 5 +-ldouble: 5 ++ildouble: 6 ++ldouble: 6 + + Function: "hypot": + double: 1 +@@ -1743,8 +1743,8 @@ double: 3 + float: 4 + idouble: 3 + ifloat: 4 +-ildouble: 5 +-ldouble: 5 ++ildouble: 6 ++ldouble: 6 + + Function: "log": + double: 1 +diff --git a/sysdeps/i386/i686/multiarch/memchr-sse2.S b/sysdeps/i386/i686/multiarch/memchr-sse2.S +index 910679cfc0..e41f324a77 100644 +--- a/sysdeps/i386/i686/multiarch/memchr-sse2.S ++++ b/sysdeps/i386/i686/multiarch/memchr-sse2.S +@@ -117,7 +117,6 @@ L(crosscache): + + # ifndef USE_AS_RAWMEMCHR + jnz L(match_case2_prolog1) +- lea -16(%edx), %edx + /* Calculate the last acceptable address and check for possible + addition overflow by using satured math: + edx = ecx + edx +@@ -125,6 +124,7 @@ L(crosscache): + add %ecx, %edx + sbb %eax, %eax + or %eax, %edx ++ sub $16, %edx + jbe L(return_null) + lea 16(%edi), %edi + # else +diff --git a/sysdeps/i386/i686/multiarch/strcspn-c.c b/sysdeps/i386/i686/multiarch/strcspn-c.c +index 6d61e190a8..ec230fb383 100644 +--- a/sysdeps/i386/i686/multiarch/strcspn-c.c ++++ b/sysdeps/i386/i686/multiarch/strcspn-c.c +@@ -1,2 +1,4 @@ +-#define __strcspn_sse2 __strcspn_ia32 +-#include ++#if IS_IN (libc) ++# define __strcspn_sse2 __strcspn_ia32 ++# include ++#endif +diff --git a/sysdeps/i386/i686/multiarch/varshift.c b/sysdeps/i386/i686/multiarch/varshift.c +index 7760b966e2..6742a35d41 100644 +--- a/sysdeps/i386/i686/multiarch/varshift.c ++++ b/sysdeps/i386/i686/multiarch/varshift.c +@@ -1 +1,3 @@ +-#include ++#if IS_IN (libc) ++# include ++#endif +diff --git a/sysdeps/mips/bits/long-double.h b/sysdeps/mips/bits/long-double.h +deleted file mode 100644 +index 604188e181..0000000000 +--- a/sysdeps/mips/bits/long-double.h ++++ /dev/null +@@ -1,23 +0,0 @@ +-/* Properties of long double type. MIPS version. +- Copyright (C) 2016-2017 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 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 +- . */ +- +-#include +- +-#if !defined __NO_LONG_DOUBLE_MATH && _MIPS_SIM == _ABIO32 +-# define __NO_LONG_DOUBLE_MATH 1 +-#endif +diff --git a/sysdeps/mips/ieee754/bits/long-double.h b/sysdeps/mips/ieee754/bits/long-double.h +new file mode 100644 +index 0000000000..604188e181 +--- /dev/null ++++ b/sysdeps/mips/ieee754/bits/long-double.h +@@ -0,0 +1,23 @@ ++/* Properties of long double type. MIPS version. ++ Copyright (C) 2016-2017 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 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 ++ . */ ++ ++#include ++ ++#if !defined __NO_LONG_DOUBLE_MATH && _MIPS_SIM == _ABIO32 ++# define __NO_LONG_DOUBLE_MATH 1 ++#endif +diff --git a/sysdeps/nptl/fork.c b/sysdeps/nptl/fork.c +index db6d721fce..4bb87e2331 100644 +--- a/sysdeps/nptl/fork.c ++++ b/sysdeps/nptl/fork.c +@@ -131,10 +131,6 @@ __libc_fork (void) + call_function_static_weak (__malloc_fork_lock_parent); + } + +-#ifndef NDEBUG +- pid_t ppid = THREAD_GETMEM (THREAD_SELF, tid); +-#endif +- + #ifdef ARCH_FORK + pid = ARCH_FORK (); + #else +@@ -147,8 +143,6 @@ __libc_fork (void) + { + struct pthread *self = THREAD_SELF; + +- assert (THREAD_GETMEM (self, tid) != ppid); +- + /* See __pthread_once. */ + if (__fork_generation_pointer != NULL) + *__fork_generation_pointer += __PTHREAD_ONCE_FORK_GEN_INCR; +@@ -230,8 +224,6 @@ __libc_fork (void) + } + else + { +- assert (THREAD_GETMEM (THREAD_SELF, tid) == ppid); +- + /* Release acquired locks in the multi-threaded case. */ + if (multiple_threads) + { +diff --git a/sysdeps/powerpc/power7/fpu/s_logbl.c b/sysdeps/powerpc/power7/fpu/s_logbl.c +index f7ecbd105a..3ae383a831 100644 +--- a/sysdeps/powerpc/power7/fpu/s_logbl.c ++++ b/sysdeps/powerpc/power7/fpu/s_logbl.c +@@ -35,14 +35,16 @@ static const union { + long double + __logbl (long double x) + { +- double xh; ++ double xh, xl; + double ret; ++ int64_t hx; + + if (__builtin_expect (x == 0.0L, 0)) + /* Raise FE_DIVBYZERO and return -HUGE_VAL[LF]. */ + return -1.0L / __builtin_fabsl (x); + +- xh = ldbl_high (x); ++ ldbl_unpack (x, &xh, &xl); ++ EXTRACT_WORDS64 (hx, xh); + /* ret = x & 0x7ff0000000000000; */ + asm ( + "xxland %x0,%x1,%x2\n" +@@ -58,10 +60,20 @@ __logbl (long double x) + { + /* POSIX specifies that denormal number is treated as + though it were normalized. */ +- int64_t hx; +- +- EXTRACT_WORDS64 (hx, xh); +- return (long double) (-1023 - (__builtin_clzll (hx) - 12)); ++ return (long double) (- (__builtin_clzll (hx & 0x7fffffffffffffffLL) \ ++ - 12) - 1023); ++ } ++ else if ((hx & 0x000fffffffffffffLL) == 0) ++ { ++ /* If the high part is a power of 2, and the low part is nonzero ++ with the opposite sign, the low part affects the ++ exponent. */ ++ int64_t lx, rhx; ++ EXTRACT_WORDS64 (lx, xl); ++ rhx = (hx & 0x7ff0000000000000LL) >> 52; ++ if ((hx ^ lx) < 0 && (lx & 0x7fffffffffffffffLL) != 0) ++ rhx--; ++ return (long double) (rhx - 1023); + } + /* Test to avoid logb_downward (0.0) == -0.0. */ + return ret == -0.0 ? 0.0 : ret; +diff --git a/sysdeps/powerpc/powerpc32/dl-machine.h b/sysdeps/powerpc/powerpc32/dl-machine.h +index 28eb50f92d..9b5a99fcc7 100644 +--- a/sysdeps/powerpc/powerpc32/dl-machine.h ++++ b/sysdeps/powerpc/powerpc32/dl-machine.h +@@ -309,7 +309,10 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc, + against local symbols. */ + if (__builtin_expect (ELF32_ST_BIND (sym->st_info) == STB_LOCAL, 0) + && sym->st_shndx != SHN_UNDEF) +- value = map->l_addr; ++ { ++ sym_map = map; ++ value = map->l_addr; ++ } + else + { + sym_map = RESOLVE_MAP (&sym, version, r_type); +diff --git a/sysdeps/sparc/sparc32/dl-machine.h b/sysdeps/sparc/sparc32/dl-machine.h +index cf7272f359..3e03fd091c 100644 +--- a/sysdeps/sparc/sparc32/dl-machine.h ++++ b/sysdeps/sparc/sparc32/dl-machine.h +@@ -375,6 +375,7 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc, + if (__builtin_expect (ELF32_ST_BIND (sym->st_info) == STB_LOCAL, 0) + && sym->st_shndx != SHN_UNDEF) + { ++ sym_map = map; + value = map->l_addr; + } + else +diff --git a/sysdeps/sparc/sparc64/dl-machine.h b/sysdeps/sparc/sparc64/dl-machine.h +index 99c00f493d..0694ac1362 100644 +--- a/sysdeps/sparc/sparc64/dl-machine.h ++++ b/sysdeps/sparc/sparc64/dl-machine.h +@@ -402,6 +402,7 @@ elf_machine_rela (struct link_map *map, const Elf64_Rela *reloc, + if (__builtin_expect (ELF64_ST_BIND (sym->st_info) == STB_LOCAL, 0) + && sym->st_shndx != SHN_UNDEF) + { ++ sym_map = map; + value = map->l_addr; + } + else +diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile +index b3d68665f9..beb1c29111 100644 +--- a/sysdeps/unix/sysv/linux/Makefile ++++ b/sysdeps/unix/sysv/linux/Makefile +@@ -141,7 +141,7 @@ endif + ifeq ($(subdir),posix) + sysdep_headers += bits/initspin.h + +-sysdep_routines += sched_getcpu ++sysdep_routines += sched_getcpu oldglob + + tests += tst-affinity tst-affinity-pid + +diff --git a/sysdeps/unix/sysv/linux/alpha/glob.c b/sysdeps/unix/sysv/linux/alpha/glob.c +index 2d7d287a25..1b813c1cfd 100644 +--- a/sysdeps/unix/sysv/linux/alpha/glob.c ++++ b/sysdeps/unix/sysv/linux/alpha/glob.c +@@ -42,10 +42,6 @@ extern void __new_globfree (glob_t *__pglob); + #undef globfree64 + + versioned_symbol (libc, __new_glob, glob, GLIBC_2_1); +-versioned_symbol (libc, __new_globfree, globfree, GLIBC_2_1); + libc_hidden_ver (__new_glob, glob) +-libc_hidden_ver (__new_globfree, globfree) + + weak_alias (__new_glob, glob64) +-weak_alias (__new_globfree, globfree64) +-libc_hidden_ver (__new_globfree, globfree64) +diff --git a/sysdeps/unix/sysv/linux/alpha/globfree.c b/sysdeps/unix/sysv/linux/alpha/globfree.c +new file mode 100644 +index 0000000000..98cf1c200b +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/alpha/globfree.c +@@ -0,0 +1,37 @@ ++/* Compat globfree. Linux/alpha version. ++ Copyright (C) 2017 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 ++ . */ ++ ++#define globfree64 __no_globfree64_decl ++#include ++#include ++#include ++ ++#define globfree(pglob) \ ++ __new_globfree (pglob) ++ ++extern void __new_globfree (glob_t *__pglob); ++ ++#include ++ ++#undef globfree64 ++ ++versioned_symbol (libc, __new_globfree, globfree, GLIBC_2_1); ++libc_hidden_ver (__new_globfree, globfree) ++ ++weak_alias (__new_globfree, globfree64) ++libc_hidden_ver (__new_globfree, globfree64) +diff --git a/sysdeps/unix/sysv/linux/alpha/localplt.data b/sysdeps/unix/sysv/linux/alpha/localplt.data +index cca17f1e34..1f0e3b494e 100644 +--- a/sysdeps/unix/sysv/linux/alpha/localplt.data ++++ b/sysdeps/unix/sysv/linux/alpha/localplt.data +@@ -20,7 +20,7 @@ libc.so: free + RELA R_ALPHA_GLOB_DAT + libc.so: malloc + RELA R_ALPHA_GLOB_DAT + libc.so: memalign + RELA R_ALPHA_GLOB_DAT + libc.so: realloc + RELA R_ALPHA_GLOB_DAT +-libm.so: matherr ++libm.so: matherr + RELA R_ALPHA_GLOB_DAT + # We used to offer inline functions that used this, so it must be exported. + # Ought to reorg things such that carg isn't thus forced to use a plt. + libm.so: __atan2 +diff --git a/sysdeps/unix/sysv/linux/hppa/bits/shm.h b/sysdeps/unix/sysv/linux/hppa/bits/shm.h +index 794f0ab2da..495dae8afc 100644 +--- a/sysdeps/unix/sysv/linux/hppa/bits/shm.h ++++ b/sysdeps/unix/sysv/linux/hppa/bits/shm.h +@@ -37,7 +37,7 @@ + #define SHM_UNLOCK 12 /* unlock segment (root only) */ + + /* Segment low boundary address multiple. */ +-#define SHMLBA 0x00400000 /* address needs to be 4 Mb aligned */ ++#define SHMLBA 0x1000 + + /* Type to count number of attaches. */ + typedef unsigned long int shmatt_t; +diff --git a/sysdeps/unix/sysv/linux/hppa/clone.S b/sysdeps/unix/sysv/linux/hppa/clone.S +index d36b302199..f6b4e3eea8 100644 +--- a/sysdeps/unix/sysv/linux/hppa/clone.S ++++ b/sysdeps/unix/sysv/linux/hppa/clone.S +@@ -64,9 +64,12 @@ + ENTRY(__clone) + /* Prologue */ + stwm %r4, 64(%sp) ++ .cfi_def_cfa_offset -64 ++ .cfi_offset 4, 0 + stw %sp, -4(%sp) + #ifdef PIC + stw %r19, -32(%sp) ++ .cfi_offset 19, 32 + #endif + + /* Sanity check arguments. */ +@@ -147,9 +150,9 @@ ENTRY(__clone) + #ifdef PIC + copy %r4, %r19 + #endif +- /* The call to _exit needs saved r19. */ +- bl _exit, %rp +- copy %ret0, %arg0 ++ copy %r28, %r26 ++ ble 0x100(%sr2, %r0) ++ ldi __NR_exit, %r20 + + /* We should not return from _exit. + We do not restore r4, or the stack state. */ +diff --git a/sysdeps/unix/sysv/linux/hppa/getcontext.S b/sysdeps/unix/sysv/linux/hppa/getcontext.S +index 6f52f2149d..68a74a0b7e 100644 +--- a/sysdeps/unix/sysv/linux/hppa/getcontext.S ++++ b/sysdeps/unix/sysv/linux/hppa/getcontext.S +@@ -130,8 +130,11 @@ ENTRY(__getcontext) + + /* Prologue */ + stwm %r4, 64(%sp) ++ .cfi_def_cfa_offset -64 ++ .cfi_offset 4, 0 + #ifdef PIC + stw %r19, -32(%sp) ++ .cfi_offset 19, 32 + #endif + + /* Set up the trampoline registers. +@@ -156,7 +159,7 @@ ENTRY(__getcontext) + /* Epilogue */ + ldw -84(%sp), %r2 + #ifdef PIC +- ldw -96(%sp), %r19 ++ ldw -32(%sp), %r19 + #endif + bv %r0(%r2) + ldwm -64(%sp), %r4 +diff --git a/sysdeps/unix/sysv/linux/hppa/internaltypes.h b/sysdeps/unix/sysv/linux/hppa/internaltypes.h +deleted file mode 100644 +index d6496579da..0000000000 +--- a/sysdeps/unix/sysv/linux/hppa/internaltypes.h ++++ /dev/null +@@ -1,84 +0,0 @@ +-#include_next +-#ifndef _INTERNAL_TYPES_H_HPPA_ +-#define _INTERNAL_TYPES_H_HPPA_ 1 +-#include +- +-/* In GLIBC 2.10 HPPA switched from Linuxthreads to NPTL, and in order +-to maintain ABI compatibility with pthread_cond_t, some care had to be +-taken. +- +-The NPTL pthread_cond_t grew in size. When HPPA switched to NPTL, we +-dropped the use of ldcw, and switched to the kernel helper routine for +-compare-and-swap. This allowed HPPA to use the 4-word 16-byte aligned +-lock words, and alignment words to store the additional pthread_cond_t +-data. Once organized properly the new NPTL pthread_cond_t was 1 word +-smaller than the Linuxthreads version. +- +-However, we were faced with the case that users may have initialized the +-pthread_cond_t with PTHREAD_COND_INITIALIZER. In this case, the first +-four words were set to one, and must be cleared before any NPTL code +-used these words. +- +-We didn't want to use LDCW, because it continues to be a source of bugs +-when applications memset pthread_cond_t to all zeroes by accident. This +-works on all other architectures where lock words are unlocked at zero. +-Remember that because of the semantics of LDCW, a locked word is set to +-zero, and an unlocked word is set to 1. +- +-Instead we used atomic_compare_and_exchange_val_acq, but we couldn't use +-this on any of the pthread_cond_t words, otherwise it might interfere +-with the current operation of the structure. To solve this problem we +-used the left over word. +- +-If the stucture was initialized by a legacy Linuxthread +-PTHREAD_COND_INITIALIZER it contained a 1, and this indicates that the +-structure requires zeroing for NPTL. The first thread to come upon a +-pthread_cond_t with a 1 in the __initializer field, will +-compare-and-swap the value, placing a 2 there which will cause all other +-threads using the same pthread_cond_t to wait for the completion of the +-initialization. Lastly, we use a store (with memory barrier) to change +-__initializer from 2 to 0. Note that the store is strongly ordered, but +-we use the PA 1.1 compatible form which is ",ma" with zero offset. +- +-In the future, when the application is recompiled with NPTL +-PTHREAD_COND_INITIALIZER it will be a quick compare-and-swap, which +-fails because __initializer is zero, and the structure will be used as +-is correctly. */ +- +-#define cond_compat_clear(var) \ +-({ \ +- int tmp = 0; \ +- var->__data.__wseq = 0; \ +- var->__data.__signals_sent = 0; \ +- var->__data.__confirmed = 0; \ +- var->__data.__generation = 0; \ +- var->__data.__mutex = NULL; \ +- var->__data.__quiescence_waiters = 0; \ +- var->__data.__clockid = 0; \ +- /* Clear __initializer last, to indicate initialization is done. */ \ +- /* This synchronizes-with the acquire load below. */ \ +- atomic_store_release (&var->__data.__initializer, 0); \ +-}) +- +-#define cond_compat_check_and_clear(var) \ +-({ \ +- int v; \ +- int *value = &var->__data.__initializer; \ +- /* This synchronizes-with the release store above. */ \ +- while ((v = atomic_load_acquire (value)) != 0) \ +- { \ +- if (v == 1 \ +- /* Relaxed MO is fine; it only matters who's first. */ \ +- && atomic_compare_exchange_acquire_weak_relaxed (value, 1, 2)) \ +- { \ +- /* We're first; initialize structure. */ \ +- cond_compat_clear (var); \ +- break; \ +- } \ +- else \ +- /* Yield before we re-check initialization status. */ \ +- sched_yield (); \ +- } \ +-}) +- +-#endif +diff --git a/sysdeps/unix/sysv/linux/hppa/ipc_priv.h b/sysdeps/unix/sysv/linux/hppa/ipc_priv.h +new file mode 100644 +index 0000000000..d880f5029a +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/hppa/ipc_priv.h +@@ -0,0 +1,21 @@ ++/* Old SysV permission definition for Linux. Hppa version. ++ Copyright (C) 2017 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 ++ . */ ++ ++#include /* For __key_t */ ++ ++#define __IPC_64 0x0 +diff --git a/sysdeps/unix/sysv/linux/hppa/localplt.data b/sysdeps/unix/sysv/linux/hppa/localplt.data +index 9dd81b47c8..db9e24b090 100644 +--- a/sysdeps/unix/sysv/linux/hppa/localplt.data ++++ b/sysdeps/unix/sysv/linux/hppa/localplt.data +@@ -6,7 +6,6 @@ libc.so: free + libc.so: malloc + libc.so: memalign + libc.so: realloc +-libc.so: _exit + libc.so: __sigsetjmp + libc.so: _IO_funlockfile + libc.so: sigprocmask +diff --git a/sysdeps/unix/sysv/linux/hppa/pt-vfork.S b/sysdeps/unix/sysv/linux/hppa/pt-vfork.S +index fc4573c86b..8b7d7df2fe 100644 +--- a/sysdeps/unix/sysv/linux/hppa/pt-vfork.S ++++ b/sysdeps/unix/sysv/linux/hppa/pt-vfork.S +@@ -58,7 +58,10 @@ ENTRY(__vfork) + that there is no child now, so it's safe to create + a frame. */ + stw %rp, -20(%sp) ++ .cfi_offset 2, -20 + stwm %r3, 64(%sp) ++ .cfi_def_cfa_offset -64 ++ .cfi_offset 3, 0 + stw %sp, -4(%sp) + + sub %r0,%ret0,%r3 +diff --git a/sysdeps/unix/sysv/linux/hppa/pthread.h b/sysdeps/unix/sysv/linux/hppa/pthread.h +index ac617201d2..806072cde4 100644 +--- a/sysdeps/unix/sysv/linux/hppa/pthread.h ++++ b/sysdeps/unix/sysv/linux/hppa/pthread.h +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + + /* Detach state. */ +@@ -82,32 +83,18 @@ enum + #endif + + +-#ifdef __PTHREAD_MUTEX_HAVE_PREV +-# define PTHREAD_MUTEX_INITIALIZER \ +- { { 0, 0, 0, 0, 0, __PTHREAD_SPINS, { 0, 0 } } } +-# ifdef __USE_GNU +-# define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \ +- { { 0, 0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, __PTHREAD_SPINS, { 0, 0 } } } +-# define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \ +- { { 0, 0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, __PTHREAD_SPINS, { 0, 0 } } } +-# define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \ +- { { 0, 0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, __PTHREAD_SPINS, { 0, 0 } } } +-# define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \ +- { { 0, 0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, __PTHREAD_SPINS, { 0, 0 } } } +- +-# endif +-#else +-# define PTHREAD_MUTEX_INITIALIZER \ +- { { 0, 0, 0, 0, 0, { __PTHREAD_SPINS } } } +-# ifdef __USE_GNU +-# define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \ +- { { 0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, 0, { __PTHREAD_SPINS } } } +-# define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \ +- { { 0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, 0, { __PTHREAD_SPINS } } } +-# define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \ +- { { 0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, 0, { __PTHREAD_SPINS } } } +- +-# endif ++#define PTHREAD_MUTEX_INITIALIZER \ ++ { { 0, 0, 0, 0, { 0, 0, 0, 0 }, 0, { __PTHREAD_SPINS }, 0, 0 } } ++#ifdef __USE_GNU ++# define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \ ++ { { 0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, { 0, 0, 0, 0 }, 0, \ ++ { __PTHREAD_SPINS }, 0, 0 } } ++# define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \ ++ { { 0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, { 0, 0, 0, 0 }, 0, \ ++ { __PTHREAD_SPINS }, 0, 0 } } ++# define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \ ++ { { 0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, { 0, 0, 0, 0 }, 0, \ ++ { __PTHREAD_SPINS }, 0, 0 } } + #endif + + +@@ -130,25 +117,14 @@ enum + # endif + #endif + ++ + /* Read-write lock initializers. */ + # define PTHREAD_RWLOCK_INITIALIZER \ +- { { 0, 0, 0, 0, 0, 0, 0, 0, __PTHREAD_RWLOCK_ELISION_EXTRA, 0, 0 } } ++ { { { 0, 0, 0, 0 }, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } + # ifdef __USE_GNU +-# ifdef __PTHREAD_RWLOCK_INT_FLAGS_SHARED +-# define PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP \ +- { { 0, 0, 0, 0, 0, 0, 0, 0, __PTHREAD_RWLOCK_ELISION_EXTRA, 0, \ +- PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP } } +-# else +-# if __BYTE_ORDER == __LITTLE_ENDIAN +-# define PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP \ +- { { 0, 0, 0, 0, 0, 0, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP, \ +- 0, __PTHREAD_RWLOCK_ELISION_EXTRA, 0, 0 } } +-# else +-# define PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP \ +- { { 0, 0, 0, 0, 0, 0, 0, 0, 0, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP,\ +- 0 } } +-# endif +-# endif ++# define PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP \ ++ { { { 0, 0, 0, 0 }, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ ++ PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP, 0, 0, 0 } } + # endif + #endif /* Unix98 or XOpen2K */ + +@@ -183,9 +159,8 @@ enum + }; + + +- + /* Conditional variable handling. */ +-#define PTHREAD_COND_INITIALIZER { { 0, 0, 0, 0, 0, (void *) 0, 0, 0 } } ++#define PTHREAD_COND_INITIALIZER { { {0}, {0}, {0, 0}, {0, 0}, 0, 0, {0, 0} } } + + + /* Cleanup buffers */ +@@ -1161,43 +1136,3 @@ __NTH (pthread_equal (pthread_t __thread1, pthread_t __thread2)) + __END_DECLS + + #endif /* pthread.h */ +- +-#ifndef _PTHREAD_H_HPPA_ +-#define _PTHREAD_H_HPPA_ 1 +- +-/* The pthread_cond_t initializer is compatible only with NPTL. We do not +- want to be forwards compatible, we eventually want to drop the code +- that has to clear the old LT initializer. */ +-#undef PTHREAD_COND_INITIALIZER +-#define PTHREAD_COND_INITIALIZER { { 0, 0, 0, (void *) 0, 0, 0, 0, 0, 0 } } +- +-/* The pthread_mutex_t and pthread_rwlock_t initializers are compatible +- only with NPTL. NPTL assumes pthread_rwlock_t is all zero. */ +-#undef PTHREAD_MUTEX_INITIALIZER +-#undef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP +-#undef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP +-#undef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP +-/* Mutex initializers. */ +-#define PTHREAD_MUTEX_INITIALIZER \ +- { { 0, 0, 0, 0, { 0, 0, 0, 0 }, 0, { 0 }, 0, 0 } } +-#ifdef __USE_GNU +-# define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \ +- { { 0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, { 0, 0, 0, 0 }, 0, { 0 }, 0, 0 } } +-# define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \ +- { { 0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, { 0, 0, 0, 0 }, 0, { 0 }, 0, 0 } } +-# define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \ +- { { 0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, { 0, 0, 0, 0 }, 0, { 0 }, 0, 0 } } +-#endif +- +-#undef PTHREAD_RWLOCK_INITIALIZER +-#undef PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP +-/* Read-write lock initializers. */ +-#define PTHREAD_RWLOCK_INITIALIZER \ +- { { { 0, 0, 0, 0 }, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } +-#ifdef __USE_GNU +-# define PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP \ +- { { { 0, 0, 0, 0 }, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP,\ +- 0, 0, 0 } } +-#endif /* Unix98 or XOpen2K */ +- +-#endif +diff --git a/sysdeps/unix/sysv/linux/hppa/pthread_cond_broadcast.c b/sysdeps/unix/sysv/linux/hppa/pthread_cond_broadcast.c +deleted file mode 100644 +index a6f9f5d433..0000000000 +--- a/sysdeps/unix/sysv/linux/hppa/pthread_cond_broadcast.c ++++ /dev/null +@@ -1,40 +0,0 @@ +-/* Copyright (C) 2009-2017 Free Software Foundation, Inc. +- This file is part of the GNU C Library. +- Contributed by Carlos O'Donell , 2009. +- +- 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 +- . */ +- +-#ifndef INCLUDED_SELF +-# define INCLUDED_SELF +-# include +-#else +-# include +-# include +-# include +-# include +-int +-__pthread_cond_broadcast (pthread_cond_t *cond) +-{ +- cond_compat_check_and_clear (cond); +- return __pthread_cond_broadcast_internal (cond); +-} +-versioned_symbol (libpthread, __pthread_cond_broadcast, pthread_cond_broadcast, +- GLIBC_2_3_2); +-# undef versioned_symbol +-# define versioned_symbol(lib, local, symbol, version) +-# undef __pthread_cond_broadcast +-# define __pthread_cond_broadcast __pthread_cond_broadcast_internal +-# include_next +-#endif +diff --git a/sysdeps/unix/sysv/linux/hppa/pthread_cond_destroy.c b/sysdeps/unix/sysv/linux/hppa/pthread_cond_destroy.c +deleted file mode 100644 +index 49af087bb4..0000000000 +--- a/sysdeps/unix/sysv/linux/hppa/pthread_cond_destroy.c ++++ /dev/null +@@ -1,40 +0,0 @@ +-/* Copyright (C) 2009-2017 Free Software Foundation, Inc. +- This file is part of the GNU C Library. +- Contributed by Carlos O'Donell , 2009. +- +- 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 +- . */ +- +-#ifndef INCLUDED_SELF +-# define INCLUDED_SELF +-# include +-#else +-# include +-# include +-# include +-# include +-int +-__pthread_cond_destroy (pthread_cond_t *cond) +-{ +- cond_compat_check_and_clear (cond); +- return __pthread_cond_destroy_internal (cond); +-} +-versioned_symbol (libpthread, __pthread_cond_destroy, pthread_cond_destroy, +- GLIBC_2_3_2); +-# undef versioned_symbol +-# define versioned_symbol(lib, local, symbol, version) +-# undef __pthread_cond_destroy +-# define __pthread_cond_destroy __pthread_cond_destroy_internal +-# include_next +-#endif +diff --git a/sysdeps/unix/sysv/linux/hppa/pthread_cond_init.c b/sysdeps/unix/sysv/linux/hppa/pthread_cond_init.c +deleted file mode 100644 +index ccb3de07ff..0000000000 +--- a/sysdeps/unix/sysv/linux/hppa/pthread_cond_init.c ++++ /dev/null +@@ -1,40 +0,0 @@ +-/* Copyright (C) 2009-2017 Free Software Foundation, Inc. +- This file is part of the GNU C Library. +- Contributed by Carlos O'Donell , 2009. +- +- 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 +- . */ +- +-#ifndef INCLUDED_SELF +-# define INCLUDED_SELF +-# include +-#else +-# include +-# include +-# include +-# include +-int +-__pthread_cond_init (pthread_cond_t *cond, const pthread_condattr_t *cond_attr) +-{ +- cond_compat_clear (cond); +- return __pthread_cond_init_internal (cond, cond_attr); +-} +-versioned_symbol (libpthread, __pthread_cond_init, pthread_cond_init, +- GLIBC_2_3_2); +-# undef versioned_symbol +-# define versioned_symbol(lib, local, symbol, version) +-# undef __pthread_cond_init +-# define __pthread_cond_init __pthread_cond_init_internal +-# include_next +-#endif +diff --git a/sysdeps/unix/sysv/linux/hppa/pthread_cond_signal.c b/sysdeps/unix/sysv/linux/hppa/pthread_cond_signal.c +deleted file mode 100644 +index 2bf32af933..0000000000 +--- a/sysdeps/unix/sysv/linux/hppa/pthread_cond_signal.c ++++ /dev/null +@@ -1,40 +0,0 @@ +-/* Copyright (C) 2009-2017 Free Software Foundation, Inc. +- This file is part of the GNU C Library. +- Contributed by Carlos O'Donell , 2009. +- +- 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 +- . */ +- +-#ifndef INCLUDED_SELF +-# define INCLUDED_SELF +-# include +-#else +-# include +-# include +-# include +-# include +-int +-__pthread_cond_signal (pthread_cond_t *cond) +-{ +- cond_compat_check_and_clear (cond); +- return __pthread_cond_signal_internal (cond); +-} +-versioned_symbol (libpthread, __pthread_cond_signal, pthread_cond_signal, +- GLIBC_2_3_2); +-# undef versioned_symbol +-# define versioned_symbol(lib, local, symbol, version) +-# undef __pthread_cond_signal +-# define __pthread_cond_signal __pthread_cond_signal_internal +-# include_next +-#endif +diff --git a/sysdeps/unix/sysv/linux/hppa/pthread_cond_wait.c b/sysdeps/unix/sysv/linux/hppa/pthread_cond_wait.c +deleted file mode 100644 +index 1cc2fc15d4..0000000000 +--- a/sysdeps/unix/sysv/linux/hppa/pthread_cond_wait.c ++++ /dev/null +@@ -1,53 +0,0 @@ +-/* Copyright (C) 2009-2017 Free Software Foundation, Inc. +- This file is part of the GNU C Library. +- Contributed by Carlos O'Donell , 2009. +- +- 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 +- . */ +- +-#ifndef INCLUDED_SELF +-# define INCLUDED_SELF +-# include +-#else +-# include +-# include +-# include +-# include +-int +-__pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex) +-{ +- cond_compat_check_and_clear (cond); +- return __pthread_cond_wait_internal (cond, mutex); +-} +-versioned_symbol (libpthread, __pthread_cond_wait, pthread_cond_wait, +- GLIBC_2_3_2); +-int +-__pthread_cond_timedwait (cond, mutex, abstime) +- pthread_cond_t *cond; +- pthread_mutex_t *mutex; +- const struct timespec *abstime; +-{ +- cond_compat_check_and_clear (cond); +- return __pthread_cond_timedwait_internal (cond, mutex, abstime); +-} +-versioned_symbol (libpthread, __pthread_cond_timedwait, pthread_cond_timedwait, +- GLIBC_2_3_2); +-# undef versioned_symbol +-# define versioned_symbol(lib, local, symbol, version) +-# undef __pthread_cond_wait +-# define __pthread_cond_wait __pthread_cond_wait_internal +-# undef __pthread_cond_timedwait +-# define __pthread_cond_timedwait __pthread_cond_timedwait_internal +-# include_next +-#endif +diff --git a/sysdeps/unix/sysv/linux/hppa/setcontext.S b/sysdeps/unix/sysv/linux/hppa/setcontext.S +index 3f4da7938f..92cb204f8d 100644 +--- a/sysdeps/unix/sysv/linux/hppa/setcontext.S ++++ b/sysdeps/unix/sysv/linux/hppa/setcontext.S +@@ -26,8 +26,11 @@ + ENTRY(__setcontext) + /* Prologue */ + stwm %r3, 64(%sp) ++ .cfi_def_cfa_offset -64 ++ .cfi_offset 3, 0 + #ifdef PIC + stw %r19, -32(%sp) ++ .cfi_offset 19, 32 + #endif + + /* Save ucp. */ +@@ -141,7 +144,7 @@ ENTRY(__setcontext) + + /* No further context available. Exit now. */ + bl HIDDEN_JUMPTARGET(exit), %r2 +- ldi -1, %r26 ++ ldi 0, %r26 + + + .Lerror: +diff --git a/sysdeps/unix/sysv/linux/hppa/sysdep-cancel.h b/sysdeps/unix/sysv/linux/hppa/sysdep-cancel.h +index 5ea297267f..8b7f2b2095 100644 +--- a/sysdeps/unix/sysv/linux/hppa/sysdep-cancel.h ++++ b/sysdeps/unix/sysv/linux/hppa/sysdep-cancel.h +@@ -62,12 +62,11 @@ + ENTRY (__##syscall_name##_nocancel) \ + DOARGS_##args ASM_LINE_SEP \ + stwm TREG, 64(%sp) ASM_LINE_SEP \ ++ .cfi_def_cfa_offset -64 ASM_LINE_SEP \ + .cfi_offset TREG, 0 ASM_LINE_SEP \ +- .cfi_adjust_cfa_offset 64 ASM_LINE_SEP \ + stw %sp, -4(%sp) ASM_LINE_SEP \ +- .cfi_offset 30, -4 ASM_LINE_SEP \ + stw %r19, -32(%sp) ASM_LINE_SEP \ +- .cfi_offset 19, -32 ASM_LINE_SEP \ ++ .cfi_offset 19, 32 ASM_LINE_SEP \ + /* Save r19 */ ASM_LINE_SEP \ + SAVE_PIC(TREG) ASM_LINE_SEP \ + /* Do syscall, delay loads # */ ASM_LINE_SEP \ +@@ -91,21 +90,19 @@ L(pre_nc_end): ASM_LINE_SEP \ + /* No need to LOAD_PIC */ ASM_LINE_SEP \ + /* Undo frame */ ASM_LINE_SEP \ + ldwm -64(%sp),TREG ASM_LINE_SEP \ +- .cfi_adjust_cfa_offset -64 ASM_LINE_SEP \ + /* Restore rp before exit */ ASM_LINE_SEP \ + ldw -20(%sp), %rp ASM_LINE_SEP \ +- .cfi_restore 2 ASM_LINE_SEP \ + ret ASM_LINE_SEP \ + END(__##syscall_name##_nocancel) ASM_LINE_SEP \ + /**********************************************/ASM_LINE_SEP \ + ENTRY (name) \ + DOARGS_##args ASM_LINE_SEP \ + stwm TREG, 64(%sp) ASM_LINE_SEP \ +- .cfi_adjust_cfa_offset 64 ASM_LINE_SEP \ ++ .cfi_def_cfa_offset -64 ASM_LINE_SEP \ ++ .cfi_offset TREG, 0 ASM_LINE_SEP \ + stw %sp, -4(%sp) ASM_LINE_SEP \ +- .cfi_offset 30, -4 ASM_LINE_SEP \ + stw %r19, -32(%sp) ASM_LINE_SEP \ +- .cfi_offset 19, -32 ASM_LINE_SEP \ ++ .cfi_offset 19, 32 ASM_LINE_SEP \ + /* Done setting up frame, continue... */ ASM_LINE_SEP \ + SINGLE_THREAD_P ASM_LINE_SEP \ + cmpib,<>,n 0,%ret0,L(pseudo_cancel) ASM_LINE_SEP \ +@@ -168,40 +165,32 @@ L(pre_end): ASM_LINE_SEP \ + /* No need to LOAD_PIC */ ASM_LINE_SEP \ + /* Undo frame */ ASM_LINE_SEP \ + ldwm -64(%sp),TREG ASM_LINE_SEP \ +- .cfi_adjust_cfa_offset -64 ASM_LINE_SEP \ + /* Restore rp before exit */ ASM_LINE_SEP \ +- ldw -20(%sp), %rp ASM_LINE_SEP \ +- .cfi_restore 2 ASM_LINE_SEP ++ ldw -20(%sp), %rp ASM_LINE_SEP + + /* Save arguments into our frame */ + # define PUSHARGS_0 /* nothing to do */ + # define PUSHARGS_1 PUSHARGS_0 stw %r26, -36(%sr0,%sp) ASM_LINE_SEP \ +- .cfi_offset 26, -36 ASM_LINE_SEP ++ .cfi_offset 26, 28 ASM_LINE_SEP + # define PUSHARGS_2 PUSHARGS_1 stw %r25, -40(%sr0,%sp) ASM_LINE_SEP \ +- .cfi_offset 25, -40 ASM_LINE_SEP ++ .cfi_offset 25, 24 ASM_LINE_SEP + # define PUSHARGS_3 PUSHARGS_2 stw %r24, -44(%sr0,%sp) ASM_LINE_SEP \ +- .cfi_offset 24, -44 ASM_LINE_SEP ++ .cfi_offset 24, 20 ASM_LINE_SEP + # define PUSHARGS_4 PUSHARGS_3 stw %r23, -48(%sr0,%sp) ASM_LINE_SEP \ +- .cfi_offset 23, -48 ASM_LINE_SEP ++ .cfi_offset 23, 16 ASM_LINE_SEP + # define PUSHARGS_5 PUSHARGS_4 stw %r22, -52(%sr0,%sp) ASM_LINE_SEP \ +- .cfi_offset 22, -52 ASM_LINE_SEP ++ .cfi_offset 22, 12 ASM_LINE_SEP + # define PUSHARGS_6 PUSHARGS_5 stw %r21, -56(%sr0,%sp) ASM_LINE_SEP \ +- .cfi_offset 21, -56 ASM_LINE_SEP ++ .cfi_offset 21, 8 ASM_LINE_SEP + + /* Bring them back from the stack */ + # define POPARGS_0 /* nothing to do */ +-# define POPARGS_1 POPARGS_0 ldw -36(%sr0,%sp), %r26 ASM_LINE_SEP \ +- .cfi_restore 26 ASM_LINE_SEP +-# define POPARGS_2 POPARGS_1 ldw -40(%sr0,%sp), %r25 ASM_LINE_SEP \ +- .cfi_restore 25 ASM_LINE_SEP +-# define POPARGS_3 POPARGS_2 ldw -44(%sr0,%sp), %r24 ASM_LINE_SEP \ +- .cfi_restore 24 ASM_LINE_SEP +-# define POPARGS_4 POPARGS_3 ldw -48(%sr0,%sp), %r23 ASM_LINE_SEP \ +- .cfi_restore 23 ASM_LINE_SEP +-# define POPARGS_5 POPARGS_4 ldw -52(%sr0,%sp), %r22 ASM_LINE_SEP \ +- .cfi_restore 22 ASM_LINE_SEP +-# define POPARGS_6 POPARGS_5 ldw -56(%sr0,%sp), %r21 ASM_LINE_SEP \ +- .cfi_restore 21 ASM_LINE_SEP ++# define POPARGS_1 POPARGS_0 ldw -36(%sr0,%sp), %r26 ASM_LINE_SEP ++# define POPARGS_2 POPARGS_1 ldw -40(%sr0,%sp), %r25 ASM_LINE_SEP ++# define POPARGS_3 POPARGS_2 ldw -44(%sr0,%sp), %r24 ASM_LINE_SEP ++# define POPARGS_4 POPARGS_3 ldw -48(%sr0,%sp), %r23 ASM_LINE_SEP ++# define POPARGS_5 POPARGS_4 ldw -52(%sr0,%sp), %r22 ASM_LINE_SEP ++# define POPARGS_6 POPARGS_5 ldw -56(%sr0,%sp), %r21 ASM_LINE_SEP + + # if IS_IN (libpthread) + # ifdef PIC +diff --git a/sysdeps/unix/sysv/linux/hppa/sysdep.h b/sysdeps/unix/sysv/linux/hppa/sysdep.h +index d8dd0431a4..c0cd59e9f5 100644 +--- a/sysdeps/unix/sysv/linux/hppa/sysdep.h ++++ b/sysdeps/unix/sysv/linux/hppa/sysdep.h +@@ -49,11 +49,9 @@ + to another function */ + #define TREG 4 + #define SAVE_PIC(SREG) \ +- copy %r19, SREG ASM_LINE_SEP \ +- .cfi_register 19, SREG ++ copy %r19, SREG + #define LOAD_PIC(LREG) \ +- copy LREG , %r19 ASM_LINE_SEP \ +- .cfi_restore 19 ++ copy LREG , %r19 + /* Inline assembly defines */ + #define TREG_ASM "%r4" /* Cant clobber r3, it holds framemarker */ + #define SAVE_ASM_PIC " copy %%r19, %" TREG_ASM "\n" +@@ -292,12 +290,11 @@ + #define DO_CALL(syscall_name, args) \ + /* Create a frame */ ASM_LINE_SEP \ + stwm TREG, 64(%sp) ASM_LINE_SEP \ ++ .cfi_def_cfa_offset -64 ASM_LINE_SEP \ + .cfi_offset TREG, 0 ASM_LINE_SEP \ +- .cfi_adjust_cfa_offset 64 ASM_LINE_SEP \ + stw %sp, -4(%sp) ASM_LINE_SEP \ +- .cfi_offset 30, -4 ASM_LINE_SEP \ + stw %r19, -32(%sp) ASM_LINE_SEP \ +- .cfi_offset 19, -32 ASM_LINE_SEP \ ++ .cfi_offset 19, 32 ASM_LINE_SEP \ + /* Save r19 */ ASM_LINE_SEP \ + SAVE_PIC(TREG) ASM_LINE_SEP \ + /* Do syscall, delay loads # */ ASM_LINE_SEP \ +@@ -320,10 +317,8 @@ + L(pre_end): ASM_LINE_SEP \ + /* Restore our frame, restoring TREG */ ASM_LINE_SEP \ + ldwm -64(%sp), TREG ASM_LINE_SEP \ +- .cfi_adjust_cfa_offset -64 ASM_LINE_SEP \ + /* Restore return pointer */ ASM_LINE_SEP \ +- ldw -20(%sp),%rp ASM_LINE_SEP \ +- .cfi_restore 2 ASM_LINE_SEP ++ ldw -20(%sp),%rp ASM_LINE_SEP + + /* We do nothing with the return, except hand it back to someone else */ + #undef DO_CALL_NOERRNO +diff --git a/sysdeps/unix/sysv/linux/i386/glob64.c b/sysdeps/unix/sysv/linux/i386/glob64.c +index f68195137e..230f9fc037 100644 +--- a/sysdeps/unix/sysv/linux/i386/glob64.c ++++ b/sysdeps/unix/sysv/linux/i386/glob64.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + + #define dirent dirent64 + #define __readdir(dirp) __readdir64 (dirp) +@@ -33,44 +34,9 @@ + #undef __stat + #define __stat(file, buf) __xstat64 (_STAT_VER, file, buf) + +-#define NO_GLOB_PATTERN_P 1 +- + #define COMPILE_GLOB64 1 + + #include + +-#include "shlib-compat.h" +- +-libc_hidden_def (globfree64) +- + versioned_symbol (libc, __glob64, glob64, GLIBC_2_2); + libc_hidden_ver (__glob64, glob64) +- +-#if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2) +- +-#include +- +-int __old_glob64 (const char *__pattern, int __flags, +- int (*__errfunc) (const char *, int), +- glob64_t *__pglob); +- +-#undef dirent +-#define dirent __old_dirent64 +-#undef GL_READDIR +-# define GL_READDIR(pglob, stream) \ +- ((struct __old_dirent64 *) (pglob)->gl_readdir (stream)) +-#undef __readdir +-#define __readdir(dirp) __old_readdir64 (dirp) +-#undef glob +-#define glob(pattern, flags, errfunc, pglob) \ +- __old_glob64 (pattern, flags, errfunc, pglob) +-#define convert_dirent __old_convert_dirent +-#define glob_in_dir __old_glob_in_dir +-#define GLOB_ATTRIBUTE attribute_compat_text_section +- +-#define GLOB_ONLY_P 1 +- +-#include +- +-compat_symbol (libc, __old_glob64, glob64, GLIBC_2_1); +-#endif +diff --git a/sysdeps/unix/sysv/linux/i386/localplt.data b/sysdeps/unix/sysv/linux/i386/localplt.data +index 2c2584956d..8ea4333846 100644 +--- a/sysdeps/unix/sysv/linux/i386/localplt.data ++++ b/sysdeps/unix/sysv/linux/i386/localplt.data +@@ -6,7 +6,7 @@ libc.so: free + REL R_386_GLOB_DAT + libc.so: malloc + REL R_386_GLOB_DAT + libc.so: memalign + REL R_386_GLOB_DAT + libc.so: realloc + REL R_386_GLOB_DAT +-libm.so: matherr ++libm.so: matherr + REL R_386_GLOB_DAT + # The main malloc is interposed into the dynamic linker, for + # allocations after the initial link (when dlopen is used). + ld.so: malloc + REL R_386_GLOB_DAT +diff --git a/sysdeps/unix/sysv/linux/ia64/ipc_priv.h b/sysdeps/unix/sysv/linux/ia64/ipc_priv.h +new file mode 100644 +index 0000000000..e602eea455 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/ia64/ipc_priv.h +@@ -0,0 +1,21 @@ ++/* Old SysV permission definition for Linux. IA64 version. ++ Copyright (C) 2017 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 ++ . */ ++ ++#include /* For __key_t */ ++ ++#define __IPC_64 0x0 +diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/globfree64.c b/sysdeps/unix/sysv/linux/mips/mips64/n64/globfree64.c +new file mode 100644 +index 0000000000..abc35fdd2b +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/globfree64.c +@@ -0,0 +1 @@ ++/* glob64 is in globfree64.c */ +diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/posix_fadvise64.c b/sysdeps/unix/sysv/linux/mips/mips64/n64/posix_fadvise64.c +index 9776ee96e5..5a6379613b 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/posix_fadvise64.c ++++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/posix_fadvise64.c +@@ -29,5 +29,7 @@ + _strong_alias (__posix_fadvise64_l64, __posix_fadvise64_l32); + compat_symbol (libc, __posix_fadvise64_l32, posix_fadvise64, GLIBC_2_2); + versioned_symbol (libc, __posix_fadvise64_l64, posix_fadvise64, GLIBC_2_3_3); ++#else ++_weak_alias (posix_fadvise, posix_fadvise64); + #endif + _strong_alias (__posix_fadvise64_l64, posix_fadvise); +diff --git a/sysdeps/unix/sysv/linux/oldglob.c b/sysdeps/unix/sysv/linux/oldglob.c +new file mode 100644 +index 0000000000..8233e57ce9 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/oldglob.c +@@ -0,0 +1,42 @@ ++#include ++ ++#if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2) ++ ++#include ++#include ++#include ++ ++#include ++ ++int __old_glob64 (const char *__pattern, int __flags, ++ int (*__errfunc) (const char *, int), ++ glob64_t *__pglob); ++libc_hidden_proto (__old_glob64); ++ ++#define dirent __old_dirent64 ++#define GL_READDIR(pglob, stream) \ ++ ((struct __old_dirent64 *) (pglob)->gl_readdir (stream)) ++#undef __readdir ++#define __readdir(dirp) __old_readdir64 (dirp) ++ ++#define glob_t glob64_t ++#define glob(pattern, flags, errfunc, pglob) \ ++ __old_glob64 (pattern, flags, errfunc, pglob) ++#define globfree(pglob) globfree64(pglob) ++ ++#define convert_dirent __old_convert_dirent ++#define glob_in_dir __old_glob_in_dir ++ ++#undef stat ++#define stat stat64 ++#undef __stat ++#define __stat(file, buf) __xstat64 (_STAT_VER, file, buf) ++ ++#define GLOB_ATTRIBUTE attribute_compat_text_section ++ ++#include ++ ++libc_hidden_def (__old_glob64); ++ ++compat_symbol (libc, __old_glob64, glob64, GLIBC_2_1); ++#endif +diff --git a/sysdeps/unix/sysv/linux/s390/pt-longjmp.c b/sysdeps/unix/sysv/linux/s390/pt-longjmp.c +index d324237edd..0221ac2cf5 100644 +--- a/sysdeps/unix/sysv/linux/s390/pt-longjmp.c ++++ b/sysdeps/unix/sysv/linux/s390/pt-longjmp.c +@@ -26,8 +26,8 @@ + /* In glibc release 2.19 new versions of longjmp-functions were introduced, + but were reverted before 2.20. Thus both versions are the same function. */ + +-strong_alias (longjmp_ifunc, __v2longjmp) ++strong_alias (longjmp_alias, __v2longjmp) + compat_symbol (libpthread, __v2longjmp, longjmp, GLIBC_2_19); +-strong_alias (siglongjmp_ifunc, __v2siglongjmp) ++strong_alias (siglongjmp_alias, __v2siglongjmp) + compat_symbol (libpthread, __v2siglongjmp, siglongjmp, GLIBC_2_19); + #endif /* SHLIB_COMPAT (libpthread, GLIBC_2_19, GLIBC_2_20)) */ +diff --git a/sysdeps/unix/sysv/linux/sparc/bits/long-double.h b/sysdeps/unix/sysv/linux/sparc/bits/long-double.h +deleted file mode 100644 +index 094e05124b..0000000000 +--- a/sysdeps/unix/sysv/linux/sparc/bits/long-double.h ++++ /dev/null +@@ -1,26 +0,0 @@ +-/* Properties of long double type. SPARC version. +- Copyright (C) 2016-2017 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 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 +- . */ +- +-#include +- +-#if !defined __NO_LONG_DOUBLE_MATH && __WORDSIZE == 32 +-# define __LONG_DOUBLE_MATH_OPTIONAL 1 +-# ifndef __LONG_DOUBLE_128__ +-# define __NO_LONG_DOUBLE_MATH 1 +-# endif +-#endif +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/bits/long-double.h b/sysdeps/unix/sysv/linux/sparc/sparc32/bits/long-double.h +new file mode 100644 +index 0000000000..094e05124b +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/sparc/sparc32/bits/long-double.h +@@ -0,0 +1,26 @@ ++/* Properties of long double type. SPARC version. ++ Copyright (C) 2016-2017 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 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 ++ . */ ++ ++#include ++ ++#if !defined __NO_LONG_DOUBLE_MATH && __WORDSIZE == 32 ++# define __LONG_DOUBLE_MATH_OPTIONAL 1 ++# ifndef __LONG_DOUBLE_128__ ++# define __NO_LONG_DOUBLE_MATH 1 ++# endif ++#endif +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/bits/long-double.h b/sysdeps/unix/sysv/linux/sparc/sparc64/bits/long-double.h +new file mode 100644 +index 0000000000..094e05124b +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/sparc/sparc64/bits/long-double.h +@@ -0,0 +1,26 @@ ++/* Properties of long double type. SPARC version. ++ Copyright (C) 2016-2017 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 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 ++ . */ ++ ++#include ++ ++#if !defined __NO_LONG_DOUBLE_MATH && __WORDSIZE == 32 ++# define __LONG_DOUBLE_MATH_OPTIONAL 1 ++# ifndef __LONG_DOUBLE_128__ ++# define __NO_LONG_DOUBLE_MATH 1 ++# endif ++#endif +diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c +index 2daf0c5ef0..ee09fb762b 100644 +--- a/sysdeps/unix/sysv/linux/spawni.c ++++ b/sysdeps/unix/sysv/linux/spawni.c +@@ -17,7 +17,6 @@ + . */ + + #include +-#include + #include + #include + #include +@@ -61,17 +60,18 @@ + #define SPAWN_ERROR 127 + + #ifdef __ia64__ +-# define CLONE(__fn, __stack, __stacksize, __flags, __args) \ +- __clone2 (__fn, __stack, __stacksize, __flags, __args, 0, 0, 0) ++# define CLONE(__fn, __stackbase, __stacksize, __flags, __args) \ ++ __clone2 (__fn, __stackbase, __stacksize, __flags, __args, 0, 0, 0) + #else + # define CLONE(__fn, __stack, __stacksize, __flags, __args) \ + __clone (__fn, __stack, __flags, __args) + #endif + +-#if _STACK_GROWS_DOWN +-# define STACK(__stack, __stack_size) (__stack + __stack_size) +-#elif _STACK_GROWS_UP ++/* Since ia64 wants the stackbase w/clone2, re-use the grows-up macro. */ ++#if _STACK_GROWS_UP || defined (__ia64__) + # define STACK(__stack, __stack_size) (__stack) ++#elif _STACK_GROWS_DOWN ++# define STACK(__stack, __stack_size) (__stack + __stack_size) + #endif + + +@@ -265,7 +265,6 @@ __spawni_child (void *arguments) + __sigprocmask (SIG_SETMASK, (attr->__flags & POSIX_SPAWN_SETSIGMASK) + ? &attr->__ss : &args->oldmask, 0); + +- args->err = 0; + args->exec (args->file, args->argv, args->envp); + + /* This is compatibility function required to enable posix_spawn run +@@ -318,6 +317,11 @@ __spawnix (pid_t * pid, const char *file, + + /* Add a slack area for child's stack. */ + size_t argv_size = (argc * sizeof (void *)) + 512; ++ /* We need at least a few pages in case the compiler's stack checking is ++ enabled. In some configs, it is known to use at least 24KiB. We use ++ 32KiB to be "safe" from anything the compiler might do. Besides, the ++ extra pages won't actually be allocated unless they get used. */ ++ argv_size += (32 * 1024); + size_t stack_size = ALIGN_UP (argv_size, GLRO(dl_pagesize)); + void *stack = __mmap (NULL, stack_size, prot, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); +@@ -331,7 +335,7 @@ __spawnix (pid_t * pid, const char *file, + + /* Child must set args.err to something non-negative - we rely on + the parent and child sharing VM. */ +- args.err = -1; ++ args.err = 0; + args.file = file; + args.exec = exec; + args.fa = file_actions; +@@ -354,12 +358,26 @@ __spawnix (pid_t * pid, const char *file, + new_pid = CLONE (__spawni_child, STACK (stack, stack_size), stack_size, + CLONE_VM | CLONE_VFORK | SIGCHLD, &args); + ++ /* It needs to collect the case where the auxiliary process was created ++ but failed to execute the file (due either any preparation step or ++ for execve itself). */ + if (new_pid > 0) + { ++ /* Also, it handles the unlikely case where the auxiliary process was ++ terminated before calling execve as if it was successfully. The ++ args.err is set to 0 as default and changed to a positive value ++ only in case of failure, so in case of premature termination ++ due a signal args.err will remain zeroed and it will be up to ++ caller to actually collect it. */ + ec = args.err; +- assert (ec >= 0); +- if (ec != 0) +- __waitpid (new_pid, NULL, 0); ++ if (ec > 0) ++ /* There still an unlikely case where the child is cancelled after ++ setting args.err, due to a positive error value. Also there is ++ possible pid reuse race (where the kernel allocated the same pid ++ to an unrelated process). Unfortunately due synchronization ++ issues where the kernel might not have the process collected ++ the waitpid below can not use WNOHANG. */ ++ __waitpid (new_pid, NULL, 0); + } + else + ec = -new_pid; +diff --git a/sysdeps/unix/sysv/linux/wordsize-64/globfree64.c b/sysdeps/unix/sysv/linux/wordsize-64/globfree64.c +new file mode 100644 +index 0000000000..af035e1514 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/wordsize-64/globfree64.c +@@ -0,0 +1,2 @@ ++/* This file is here so sysdeps/gnu/glob64.c doesn't take precedence. */ ++#include +diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/globfree.c b/sysdeps/unix/sysv/linux/x86_64/x32/globfree.c +new file mode 100644 +index 0000000000..b76a761c17 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/x86_64/x32/globfree.c +@@ -0,0 +1 @@ ++#include +diff --git a/sysdeps/wordsize-64/glob.c b/sysdeps/wordsize-64/glob.c +index 082faf1c70..954e8d37e2 100644 +--- a/sysdeps/wordsize-64/glob.c ++++ b/sysdeps/wordsize-64/glob.c +@@ -4,5 +4,3 @@ + #undef glob64 + #undef globfree64 + weak_alias (glob, glob64) +-weak_alias (globfree, globfree64) +-libc_hidden_ver (globfree, globfree64) +diff --git a/sysdeps/wordsize-64/globfree.c b/sysdeps/wordsize-64/globfree.c +new file mode 100644 +index 0000000000..ec8c35b489 +--- /dev/null ++++ b/sysdeps/wordsize-64/globfree.c +@@ -0,0 +1,5 @@ ++#define globfree64 __no_globfree64_decl ++#include ++#undef globfree64 ++weak_alias (globfree, globfree64) ++libc_hidden_ver (globfree, globfree64) +diff --git a/sysdeps/wordsize-64/globfree64.c b/sysdeps/wordsize-64/globfree64.c +new file mode 100644 +index 0000000000..a0f57ff4b3 +--- /dev/null ++++ b/sysdeps/wordsize-64/globfree64.c +@@ -0,0 +1 @@ ++/* globfree64 is in globfree.c */ +diff --git a/sysdeps/x86/cpu-features-offsets.sym b/sysdeps/x86/cpu-features-offsets.sym +index f6739fae81..33dd094e37 100644 +--- a/sysdeps/x86/cpu-features-offsets.sym ++++ b/sysdeps/x86/cpu-features-offsets.sym +@@ -15,6 +15,7 @@ CPUID_ECX_OFFSET offsetof (struct cpuid_registers, ecx) + CPUID_EDX_OFFSET offsetof (struct cpuid_registers, edx) + FAMILY_OFFSET offsetof (struct cpu_features, family) + MODEL_OFFSET offsetof (struct cpu_features, model) ++XSAVE_STATE_SIZE_OFFSET offsetof (struct cpu_features, xsave_state_size) + FEATURE_OFFSET offsetof (struct cpu_features, feature) + FEATURE_SIZE sizeof (unsigned int) + +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index 1c714a4017..38012912be 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -18,6 +18,7 @@ + + #include + #include ++#include + + static void + get_common_indeces (struct cpu_features *cpu_features, +@@ -93,6 +94,71 @@ get_common_indeces (struct cpu_features *cpu_features, + } + } + } ++ ++ /* For _dl_runtime_resolve, set xsave_state_size to xsave area ++ size + integer register save size and align it to 64 bytes. */ ++ if (cpu_features->max_cpuid >= 0xd) ++ { ++ unsigned int eax, ebx, ecx, edx; ++ ++ __cpuid_count (0xd, 0, eax, ebx, ecx, edx); ++ if (ebx != 0) ++ { ++ cpu_features->xsave_state_size ++ = ALIGN_UP (ebx + STATE_SAVE_OFFSET, 64); ++ ++ __cpuid_count (0xd, 1, eax, ebx, ecx, edx); ++ ++ /* Check if XSAVEC is available. */ ++ if ((eax & (1 << 1)) != 0) ++ { ++ unsigned int xstate_comp_offsets[32]; ++ unsigned int xstate_comp_sizes[32]; ++ unsigned int i; ++ ++ xstate_comp_offsets[0] = 0; ++ xstate_comp_offsets[1] = 160; ++ xstate_comp_offsets[2] = 576; ++ xstate_comp_sizes[0] = 160; ++ xstate_comp_sizes[1] = 256; ++ ++ for (i = 2; i < 32; i++) ++ { ++ if ((STATE_SAVE_MASK & (1 << i)) != 0) ++ { ++ __cpuid_count (0xd, i, eax, ebx, ecx, edx); ++ xstate_comp_sizes[i] = eax; ++ } ++ else ++ { ++ ecx = 0; ++ xstate_comp_sizes[i] = 0; ++ } ++ ++ if (i > 2) ++ { ++ xstate_comp_offsets[i] ++ = (xstate_comp_offsets[i - 1] ++ + xstate_comp_sizes[i -1]); ++ if ((ecx & (1 << 1)) != 0) ++ xstate_comp_offsets[i] ++ = ALIGN_UP (xstate_comp_offsets[i], 64); ++ } ++ } ++ ++ /* Use XSAVEC. */ ++ unsigned int size ++ = xstate_comp_offsets[31] + xstate_comp_sizes[31]; ++ if (size) ++ { ++ cpu_features->xsave_state_size ++ = ALIGN_UP (size + STATE_SAVE_OFFSET, 64); ++ cpu_features->feature[index_arch_XSAVEC_Usable] ++ |= bit_arch_XSAVEC_Usable; ++ } ++ } ++ } ++ } + } + } + +@@ -139,8 +205,6 @@ init_cpu_features (struct cpu_features *cpu_features) + + case 0x57: + /* Knights Landing. Enable Silvermont optimizations. */ +- cpu_features->feature[index_arch_Prefer_No_VZEROUPPER] +- |= bit_arch_Prefer_No_VZEROUPPER; + + case 0x5c: + case 0x5f: +@@ -226,19 +290,15 @@ init_cpu_features (struct cpu_features *cpu_features) + cpu_features->feature[index_arch_AVX_Fast_Unaligned_Load] + |= bit_arch_AVX_Fast_Unaligned_Load; + +- /* To avoid SSE transition penalty, use _dl_runtime_resolve_slow. +- If XGETBV suports ECX == 1, use _dl_runtime_resolve_opt. */ +- cpu_features->feature[index_arch_Use_dl_runtime_resolve_slow] +- |= bit_arch_Use_dl_runtime_resolve_slow; +- if (cpu_features->max_cpuid >= 0xd) +- { +- unsigned int eax; +- +- __cpuid_count (0xd, 1, eax, ebx, ecx, edx); +- if ((eax & (1 << 2)) != 0) +- cpu_features->feature[index_arch_Use_dl_runtime_resolve_opt] +- |= bit_arch_Use_dl_runtime_resolve_opt; +- } ++ /* Since AVX512ER is unique to Xeon Phi, set Prefer_No_VZEROUPPER ++ if AVX512ER is available. Don't use AVX512 to avoid lower CPU ++ frequency if AVX512ER isn't available. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, AVX512ER)) ++ cpu_features->feature[index_arch_Prefer_No_VZEROUPPER] ++ |= bit_arch_Prefer_No_VZEROUPPER; ++ else ++ cpu_features->feature[index_arch_Prefer_No_AVX512] ++ |= bit_arch_Prefer_No_AVX512; + } + /* This spells out "AuthenticAMD". */ + else if (ebx == 0x68747541 && ecx == 0x444d4163 && edx == 0x69746e65) +diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h +index 95f0fcff87..af83a28512 100644 +--- a/sysdeps/x86/cpu-features.h ++++ b/sysdeps/x86/cpu-features.h +@@ -37,8 +37,8 @@ + #define bit_arch_Prefer_No_VZEROUPPER (1 << 17) + #define bit_arch_Fast_Unaligned_Copy (1 << 18) + #define bit_arch_Prefer_ERMS (1 << 19) +-#define bit_arch_Use_dl_runtime_resolve_opt (1 << 20) +-#define bit_arch_Use_dl_runtime_resolve_slow (1 << 21) ++#define bit_arch_Prefer_No_AVX512 (1 << 20) ++#define bit_arch_XSAVEC_Usable (1 << 21) + + /* CPUID Feature flags. */ + +@@ -62,6 +62,11 @@ + #define bit_cpu_AVX2 (1 << 5) + #define bit_cpu_AVX512F (1 << 16) + #define bit_cpu_AVX512DQ (1 << 17) ++#define bit_cpu_AVX512PF (1 << 26) ++#define bit_cpu_AVX512ER (1 << 27) ++#define bit_cpu_AVX512CD (1 << 28) ++#define bit_cpu_AVX512BW (1 << 30) ++#define bit_cpu_AVX512VL (1u << 31) + + /* XCR0 Feature flags. */ + #define bit_XMM_state (1 << 1) +@@ -76,6 +81,15 @@ + /* The current maximum size of the feature integer bit array. */ + #define FEATURE_INDEX_MAX 1 + ++/* Offset for fxsave/xsave area used by _dl_runtime_resolve. Also need ++ space to preserve RCX, RDX, RSI, RDI, R8, R9 and RAX. It must be ++ aligned to 16 bytes for fxsave and 64 bytes for xsave. */ ++#define STATE_SAVE_OFFSET (8 * 7 + 8) ++ ++/* Save SSE, AVX, AVX512, mask and bound registers. */ ++#define STATE_SAVE_MASK \ ++ ((1 << 1) | (1 << 2) | (1 << 3) | (1 << 5) | (1 << 6) | (1 << 7)) ++ + #ifdef __ASSEMBLER__ + + # include +@@ -111,6 +125,7 @@ + # define index_arch_Prefer_ERMS FEATURE_INDEX_1*FEATURE_SIZE + # define index_arch_Use_dl_runtime_resolve_opt FEATURE_INDEX_1*FEATURE_SIZE + # define index_arch_Use_dl_runtime_resolve_slow FEATURE_INDEX_1*FEATURE_SIZE ++# define index_arch_Prefer_No_AVX512 FEATURE_INDEX_1*FEATURE_SIZE + + + # if defined (_LIBC) && !IS_IN (nonlib) +@@ -199,6 +214,12 @@ struct cpu_features + } cpuid[COMMON_CPUID_INDEX_MAX]; + unsigned int family; + unsigned int model; ++ /* The type must be unsigned long int so that we use ++ ++ sub xsave_state_size_offset(%rip) %RSP_LP ++ ++ in _dl_runtime_resolve. */ ++ unsigned long int xsave_state_size; + unsigned int feature[FEATURE_INDEX_MAX]; + }; + +@@ -236,6 +257,11 @@ extern const struct cpu_features *__get_cpu_features (void) + # define index_cpu_AVX2 COMMON_CPUID_INDEX_7 + # define index_cpu_AVX512F COMMON_CPUID_INDEX_7 + # define index_cpu_AVX512DQ COMMON_CPUID_INDEX_7 ++# define index_cpu_AVX512PF COMMON_CPUID_INDEX_7 ++# define index_cpu_AVX512ER COMMON_CPUID_INDEX_7 ++# define index_cpu_AVX512CD COMMON_CPUID_INDEX_7 ++# define index_cpu_AVX512BW COMMON_CPUID_INDEX_7 ++# define index_cpu_AVX512VL COMMON_CPUID_INDEX_7 + # define index_cpu_ERMS COMMON_CPUID_INDEX_7 + # define index_cpu_RTM COMMON_CPUID_INDEX_7 + # define index_cpu_FMA COMMON_CPUID_INDEX_1 +@@ -254,6 +280,11 @@ extern const struct cpu_features *__get_cpu_features (void) + # define reg_AVX2 ebx + # define reg_AVX512F ebx + # define reg_AVX512DQ ebx ++# define reg_AVX512PF ebx ++# define reg_AVX512ER ebx ++# define reg_AVX512CD ebx ++# define reg_AVX512BW ebx ++# define reg_AVX512VL ebx + # define reg_ERMS ebx + # define reg_RTM ebx + # define reg_FMA ecx +@@ -281,8 +312,8 @@ extern const struct cpu_features *__get_cpu_features (void) + # define index_arch_Prefer_No_VZEROUPPER FEATURE_INDEX_1 + # define index_arch_Fast_Unaligned_Copy FEATURE_INDEX_1 + # define index_arch_Prefer_ERMS FEATURE_INDEX_1 +-# define index_arch_Use_dl_runtime_resolve_opt FEATURE_INDEX_1 +-# define index_arch_Use_dl_runtime_resolve_slow FEATURE_INDEX_1 ++# define index_arch_Prefer_No_AVX512 FEATURE_INDEX_1 ++# define index_arch_XSAVEC_Usable FEATURE_INDEX_1 + + #endif /* !__ASSEMBLER__ */ + +diff --git a/sysdeps/x86/fpu/test-math-vector-sincos.h b/sysdeps/x86/fpu/test-math-vector-sincos.h +index 5043b32563..95282a3ac7 100644 +--- a/sysdeps/x86/fpu/test-math-vector-sincos.h ++++ b/sysdeps/x86/fpu/test-math-vector-sincos.h +@@ -17,14 +17,14 @@ + License along with the GNU C Library; if not, see + . */ + +-#define INIT_VEC_PTRS_LOOP(vec, val, len) \ +- do \ +- { \ +- for (i = 0; i < len; i++) \ +- { \ +- vec[i] = &val[i]; \ +- } \ +- } \ ++#define INIT_VEC_PTRS_LOOP(vec, val, len) \ ++ do \ ++ { \ ++ union { VEC_INT_TYPE v; __typeof__ ((val)[0]) *a[(len)]; } u; \ ++ for (i = 0; i < len; i++) \ ++ u.a[i] = &(val)[i]; \ ++ (vec) = u.v; \ ++ } \ + while (0) + + /* Wrapper for vector sincos/sincosf compatible with x86_64 and x32 variants +@@ -40,8 +40,8 @@ void scalar_func (FLOAT x, FLOAT * r, FLOAT * r1) \ + VEC_TYPE mx; \ + VEC_INT_TYPE mr, mr1; \ + INIT_VEC_LOOP (mx, x, VEC_LEN); \ +- INIT_VEC_PTRS_LOOP (((FLOAT **) &mr), r_loc, VEC_LEN); \ +- INIT_VEC_PTRS_LOOP (((FLOAT **) &mr1), r1_loc, VEC_LEN); \ ++ INIT_VEC_PTRS_LOOP (mr, r_loc, VEC_LEN); \ ++ INIT_VEC_PTRS_LOOP (mr1, r1_loc, VEC_LEN); \ + vector_func (mx, mr, mr1); \ + TEST_VEC_LOOP (r_loc, VEC_LEN); \ + TEST_VEC_LOOP (r1_loc, VEC_LEN); \ +@@ -63,8 +63,8 @@ void scalar_func (FLOAT x, FLOAT * r, FLOAT * r1) \ + VEC_TYPE mx; \ + VEC_INT_TYPE mr, mr1; \ + INIT_VEC_LOOP (mx, x, VEC_LEN); \ +- INIT_VEC_PTRS_LOOP (((FLOAT **) &mr), r_loc, VEC_LEN/2); \ +- INIT_VEC_PTRS_LOOP (((FLOAT **) &mr1), r1_loc, VEC_LEN/2); \ ++ INIT_VEC_PTRS_LOOP (mr, r_loc, VEC_LEN/2); \ ++ INIT_VEC_PTRS_LOOP (mr1, r1_loc, VEC_LEN/2); \ + vector_func (mx, mr, mr, mr1, mr1); \ + TEST_VEC_LOOP (r_loc, VEC_LEN/2); \ + TEST_VEC_LOOP (r1_loc, VEC_LEN/2); \ +@@ -87,8 +87,8 @@ void scalar_func (FLOAT x, FLOAT * r, FLOAT * r1) \ + VEC_TYPE mx; \ + VEC_INT_TYPE mr, mr1; \ + INIT_VEC_LOOP (mx, x, VEC_LEN); \ +- INIT_VEC_PTRS_LOOP (((FLOAT **) &mr), r_loc, VEC_LEN/4); \ +- INIT_VEC_PTRS_LOOP (((FLOAT **) &mr1), r1_loc, VEC_LEN/4); \ ++ INIT_VEC_PTRS_LOOP (mr, r_loc, VEC_LEN/4); \ ++ INIT_VEC_PTRS_LOOP (mr1, r1_loc, VEC_LEN/4); \ + vector_func (mx, mr, mr, mr, mr, mr1, mr1, mr1, mr1); \ + TEST_VEC_LOOP (r_loc, VEC_LEN/4); \ + TEST_VEC_LOOP (r1_loc, VEC_LEN/4); \ +diff --git a/sysdeps/x86_64/Makefile b/sysdeps/x86_64/Makefile +index 5f25893dc9..132470d9cb 100644 +--- a/sysdeps/x86_64/Makefile ++++ b/sysdeps/x86_64/Makefile +@@ -27,7 +27,7 @@ ifeq ($(subdir),elf) + CFLAGS-.os += $(if $(filter $(@F),$(patsubst %,%.os,$(all-rtld-routines))),\ + -mno-mmx) + +-sysdep-dl-routines += tlsdesc dl-tlsdesc ++sysdep-dl-routines += tlsdesc dl-tlsdesc tls_get_addr + + tests += ifuncmain8 + modules-names += ifuncmod8 +@@ -52,9 +52,12 @@ $(objpfx)tst-quad2pie: $(objpfx)tst-quadmod2pie.o + CFLAGS-tst-quad1pie.c = $(PIE-ccflag) + CFLAGS-tst-quad2pie.c = $(PIE-ccflag) + +-tests += tst-audit3 tst-audit4 tst-audit5 tst-audit6 tst-audit7 tst-audit10 +-test-extras += tst-audit4-aux tst-audit10-aux +-extra-test-objs += tst-audit4-aux.o tst-audit10-aux.o ++tests += tst-audit3 tst-audit4 tst-audit5 tst-audit6 tst-audit7 \ ++ tst-audit10 tst-sse tst-avx tst-avx512 ++test-extras += tst-audit4-aux tst-audit10-aux \ ++ tst-avx-aux tst-avx512-aux ++extra-test-objs += tst-audit4-aux.o tst-audit10-aux.o \ ++ tst-avx-aux.o tst-avx512-aux.o + + tests += tst-split-dynreloc + LDFLAGS-tst-split-dynreloc = -Wl,-T,$(..)sysdeps/x86_64/tst-split-dynreloc.lds +@@ -65,7 +68,8 @@ modules-names += tst-auditmod3a tst-auditmod3b \ + tst-auditmod5a tst-auditmod5b \ + tst-auditmod6a tst-auditmod6b tst-auditmod6c \ + tst-auditmod7a tst-auditmod7b \ +- tst-auditmod10a tst-auditmod10b ++ tst-auditmod10a tst-auditmod10b \ ++ tst-ssemod tst-avxmod tst-avx512mod + + $(objpfx)tst-audit3: $(objpfx)tst-auditmod3a.so + $(objpfx)tst-audit3.out: $(objpfx)tst-auditmod3b.so +@@ -92,6 +96,10 @@ $(objpfx)tst-audit10: $(objpfx)tst-audit10-aux.o $(objpfx)tst-auditmod10a.so + $(objpfx)tst-audit10.out: $(objpfx)tst-auditmod10b.so + tst-audit10-ENV = LD_AUDIT=$(objpfx)tst-auditmod10b.so + ++$(objpfx)tst-sse: $(objpfx)tst-ssemod.so ++$(objpfx)tst-avx: $(objpfx)tst-avx-aux.o $(objpfx)tst-avxmod.so ++$(objpfx)tst-avx512: $(objpfx)tst-avx512-aux.o $(objpfx)tst-avx512mod.so ++ + AVX-CFLAGS=-mavx -mno-vzeroupper + CFLAGS-tst-audit4-aux.c += $(AVX-CFLAGS) + CFLAGS-tst-auditmod4a.c += $(AVX-CFLAGS) +@@ -99,14 +107,18 @@ CFLAGS-tst-auditmod4b.c += $(AVX-CFLAGS) + CFLAGS-tst-auditmod6b.c += $(AVX-CFLAGS) + CFLAGS-tst-auditmod6c.c += $(AVX-CFLAGS) + CFLAGS-tst-auditmod7b.c += $(AVX-CFLAGS) ++CFLAGS-tst-avx-aux.c += $(AVX-CFLAGS) ++CFLAGS-tst-avxmod.c += $(AVX-CFLAGS) + ifeq (yes,$(config-cflags-avx512)) + AVX512-CFLAGS = -mavx512f + CFLAGS-tst-audit10-aux.c += $(AVX512-CFLAGS) + CFLAGS-tst-auditmod10a.c += $(AVX512-CFLAGS) + CFLAGS-tst-auditmod10b.c += $(AVX512-CFLAGS) ++CFLAGS-tst-avx512-aux.c += $(AVX512-CFLAGS) ++CFLAGS-tst-avx512mod.c += $(AVX512-CFLAGS) + endif + endif + + ifeq ($(subdir),csu) +-gen-as-const-headers += tlsdesc.sym ++gen-as-const-headers += tlsdesc.sym rtld-offsets.sym + endif +diff --git a/sysdeps/x86_64/dl-machine.h b/sysdeps/x86_64/dl-machine.h +index daf4d8c070..be0b8616ea 100644 +--- a/sysdeps/x86_64/dl-machine.h ++++ b/sysdeps/x86_64/dl-machine.h +@@ -66,12 +66,9 @@ static inline int __attribute__ ((unused, always_inline)) + elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) + { + Elf64_Addr *got; +- extern void _dl_runtime_resolve_sse (ElfW(Word)) attribute_hidden; +- extern void _dl_runtime_resolve_avx (ElfW(Word)) attribute_hidden; +- extern void _dl_runtime_resolve_avx_slow (ElfW(Word)) attribute_hidden; +- extern void _dl_runtime_resolve_avx_opt (ElfW(Word)) attribute_hidden; +- extern void _dl_runtime_resolve_avx512 (ElfW(Word)) attribute_hidden; +- extern void _dl_runtime_resolve_avx512_opt (ElfW(Word)) attribute_hidden; ++ extern void _dl_runtime_resolve_fxsave (ElfW(Word)) attribute_hidden; ++ extern void _dl_runtime_resolve_xsave (ElfW(Word)) attribute_hidden; ++ extern void _dl_runtime_resolve_xsavec (ElfW(Word)) attribute_hidden; + extern void _dl_runtime_profile_sse (ElfW(Word)) attribute_hidden; + extern void _dl_runtime_profile_avx (ElfW(Word)) attribute_hidden; + extern void _dl_runtime_profile_avx512 (ElfW(Word)) attribute_hidden; +@@ -120,29 +117,14 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) + /* This function will get called to fix up the GOT entry + indicated by the offset on the stack, and then jump to + the resolved address. */ +- if (HAS_ARCH_FEATURE (AVX512F_Usable)) +- { +- if (HAS_ARCH_FEATURE (Use_dl_runtime_resolve_opt)) +- *(ElfW(Addr) *) (got + 2) +- = (ElfW(Addr)) &_dl_runtime_resolve_avx512_opt; +- else +- *(ElfW(Addr) *) (got + 2) +- = (ElfW(Addr)) &_dl_runtime_resolve_avx512; +- } +- else if (HAS_ARCH_FEATURE (AVX_Usable)) +- { +- if (HAS_ARCH_FEATURE (Use_dl_runtime_resolve_opt)) +- *(ElfW(Addr) *) (got + 2) +- = (ElfW(Addr)) &_dl_runtime_resolve_avx_opt; +- else if (HAS_ARCH_FEATURE (Use_dl_runtime_resolve_slow)) +- *(ElfW(Addr) *) (got + 2) +- = (ElfW(Addr)) &_dl_runtime_resolve_avx_slow; +- else +- *(ElfW(Addr) *) (got + 2) +- = (ElfW(Addr)) &_dl_runtime_resolve_avx; +- } ++ if (GLRO(dl_x86_cpu_features).xsave_state_size != 0) ++ *(ElfW(Addr) *) (got + 2) ++ = (HAS_ARCH_FEATURE (XSAVEC_Usable) ++ ? (ElfW(Addr)) &_dl_runtime_resolve_xsavec ++ : (ElfW(Addr)) &_dl_runtime_resolve_xsave); + else +- *(ElfW(Addr) *) (got + 2) = (ElfW(Addr)) &_dl_runtime_resolve_sse; ++ *(ElfW(Addr) *) (got + 2) ++ = (ElfW(Addr)) &_dl_runtime_resolve_fxsave; + } + } + +diff --git a/sysdeps/x86_64/dl-tls.c b/sysdeps/x86_64/dl-tls.c +new file mode 100644 +index 0000000000..3584805c8e +--- /dev/null ++++ b/sysdeps/x86_64/dl-tls.c +@@ -0,0 +1,53 @@ ++/* Thread-local storage handling in the ELF dynamic linker. x86-64 version. ++ Copyright (C) 2017 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 ++ . */ ++ ++#ifdef SHARED ++/* Work around GCC PR58066, due to which __tls_get_addr may be called ++ with an unaligned stack. The compat implementation is in ++ tls_get_addr-compat.S. */ ++ ++# include ++ ++/* Define __tls_get_addr within elf/dl-tls.c under a different ++ name. */ ++extern __typeof__ (__tls_get_addr) ___tls_get_addr; ++ ++# define __tls_get_addr ___tls_get_addr ++# include ++# undef __tls_get_addr ++ ++hidden_ver (___tls_get_addr, __tls_get_addr) ++ ++/* Only handle slow paths for __tls_get_addr. */ ++attribute_hidden ++void * ++__tls_get_addr_slow (GET_ADDR_ARGS) ++{ ++ dtv_t *dtv = THREAD_DTV (); ++ ++ if (__glibc_unlikely (dtv[0].counter != GL(dl_tls_generation))) ++ return update_get_addr (GET_ADDR_PARAM); ++ ++ return tls_get_addr_tail (GET_ADDR_PARAM, dtv, NULL); ++} ++#else ++ ++/* No compatibility symbol needed. */ ++# include ++ ++#endif +diff --git a/sysdeps/x86_64/dl-tls.h b/sysdeps/x86_64/dl-tls.h +index 4a59d2a924..c2fb56c0a1 100644 +--- a/sysdeps/x86_64/dl-tls.h ++++ b/sysdeps/x86_64/dl-tls.h +@@ -16,6 +16,9 @@ + License along with the GNU C Library; if not, see + . */ + ++#ifndef _X86_64_DL_TLS_H ++#define _X86_64_DL_TLS_H ++ + #include + + /* Type used for the representation of TLS information in the GOT. */ +@@ -27,3 +30,5 @@ typedef struct dl_tls_index + + + extern void *__tls_get_addr (tls_index *ti); ++ ++#endif /* _X86_64_DL_TLS_H */ +diff --git a/sysdeps/x86_64/dl-trampoline.S b/sysdeps/x86_64/dl-trampoline.S +index 33d7fcf7d0..a645572e44 100644 +--- a/sysdeps/x86_64/dl-trampoline.S ++++ b/sysdeps/x86_64/dl-trampoline.S +@@ -34,41 +34,24 @@ + # define DL_STACK_ALIGNMENT 8 + #endif + +-#ifndef DL_RUNTIME_UNALIGNED_VEC_SIZE +-/* The maximum size in bytes of unaligned vector load and store in the +- dynamic linker. Since SSE optimized memory/string functions with +- aligned SSE register load and store are used in the dynamic linker, +- we must set this to 8 so that _dl_runtime_resolve_sse will align the +- stack before calling _dl_fixup. */ +-# define DL_RUNTIME_UNALIGNED_VEC_SIZE 8 +-#endif +- +-/* True if _dl_runtime_resolve should align stack to VEC_SIZE bytes. */ ++/* True if _dl_runtime_resolve should align stack for STATE_SAVE or align ++ stack to 16 bytes before calling _dl_fixup. */ + #define DL_RUNTIME_RESOLVE_REALIGN_STACK \ +- (VEC_SIZE > DL_STACK_ALIGNMENT \ +- && VEC_SIZE > DL_RUNTIME_UNALIGNED_VEC_SIZE) +- +-/* Align vector register save area to 16 bytes. */ +-#define REGISTER_SAVE_VEC_OFF 0 ++ (STATE_SAVE_ALIGNMENT > DL_STACK_ALIGNMENT \ ++ || 16 > DL_STACK_ALIGNMENT) + + /* Area on stack to save and restore registers used for parameter + passing when calling _dl_fixup. */ + #ifdef __ILP32__ +-# define REGISTER_SAVE_RAX (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 8) + # define PRESERVE_BND_REGS_PREFIX + #else +-/* Align bound register save area to 16 bytes. */ +-# define REGISTER_SAVE_BND0 (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 8) +-# define REGISTER_SAVE_BND1 (REGISTER_SAVE_BND0 + 16) +-# define REGISTER_SAVE_BND2 (REGISTER_SAVE_BND1 + 16) +-# define REGISTER_SAVE_BND3 (REGISTER_SAVE_BND2 + 16) +-# define REGISTER_SAVE_RAX (REGISTER_SAVE_BND3 + 16) + # ifdef HAVE_MPX_SUPPORT + # define PRESERVE_BND_REGS_PREFIX bnd + # else + # define PRESERVE_BND_REGS_PREFIX .byte 0xf2 + # endif + #endif ++#define REGISTER_SAVE_RAX 0 + #define REGISTER_SAVE_RCX (REGISTER_SAVE_RAX + 8) + #define REGISTER_SAVE_RDX (REGISTER_SAVE_RCX + 8) + #define REGISTER_SAVE_RSI (REGISTER_SAVE_RDX + 8) +@@ -80,69 +63,56 @@ + + #define VEC_SIZE 64 + #define VMOVA vmovdqa64 +-#if DL_RUNTIME_RESOLVE_REALIGN_STACK || VEC_SIZE <= DL_STACK_ALIGNMENT +-# define VMOV vmovdqa64 +-#else +-# define VMOV vmovdqu64 +-#endif + #define VEC(i) zmm##i +-#define _dl_runtime_resolve _dl_runtime_resolve_avx512 +-#define _dl_runtime_resolve_opt _dl_runtime_resolve_avx512_opt + #define _dl_runtime_profile _dl_runtime_profile_avx512 + #include "dl-trampoline.h" +-#undef _dl_runtime_resolve +-#undef _dl_runtime_resolve_opt + #undef _dl_runtime_profile + #undef VEC +-#undef VMOV + #undef VMOVA + #undef VEC_SIZE + + #define VEC_SIZE 32 + #define VMOVA vmovdqa +-#if DL_RUNTIME_RESOLVE_REALIGN_STACK || VEC_SIZE <= DL_STACK_ALIGNMENT +-# define VMOV vmovdqa +-#else +-# define VMOV vmovdqu +-#endif + #define VEC(i) ymm##i +-#define _dl_runtime_resolve _dl_runtime_resolve_avx +-#define _dl_runtime_resolve_opt _dl_runtime_resolve_avx_opt + #define _dl_runtime_profile _dl_runtime_profile_avx + #include "dl-trampoline.h" +-#undef _dl_runtime_resolve +-#undef _dl_runtime_resolve_opt + #undef _dl_runtime_profile + #undef VEC +-#undef VMOV + #undef VMOVA + #undef VEC_SIZE + + /* movaps/movups is 1-byte shorter. */ + #define VEC_SIZE 16 + #define VMOVA movaps +-#if DL_RUNTIME_RESOLVE_REALIGN_STACK || VEC_SIZE <= DL_STACK_ALIGNMENT +-# define VMOV movaps +-#else +-# define VMOV movups +-#endif + #define VEC(i) xmm##i +-#define _dl_runtime_resolve _dl_runtime_resolve_sse + #define _dl_runtime_profile _dl_runtime_profile_sse + #undef RESTORE_AVX + #include "dl-trampoline.h" +-#undef _dl_runtime_resolve + #undef _dl_runtime_profile +-#undef VMOV ++#undef VEC + #undef VMOVA ++#undef VEC_SIZE + +-/* Used by _dl_runtime_resolve_avx_opt/_dl_runtime_resolve_avx512_opt +- to preserve the full vector registers with zero upper bits. */ +-#define VMOVA vmovdqa +-#if DL_RUNTIME_RESOLVE_REALIGN_STACK || VEC_SIZE <= DL_STACK_ALIGNMENT +-# define VMOV vmovdqa +-#else +-# define VMOV vmovdqu +-#endif +-#define _dl_runtime_resolve _dl_runtime_resolve_sse_vex ++#define USE_FXSAVE ++#define STATE_SAVE_ALIGNMENT 16 ++#define _dl_runtime_resolve _dl_runtime_resolve_fxsave ++#include "dl-trampoline.h" ++#undef _dl_runtime_resolve ++#undef USE_FXSAVE ++#undef STATE_SAVE_ALIGNMENT ++ ++#define USE_XSAVE ++#define STATE_SAVE_ALIGNMENT 64 ++#define _dl_runtime_resolve _dl_runtime_resolve_xsave ++#include "dl-trampoline.h" ++#undef _dl_runtime_resolve ++#undef USE_XSAVE ++#undef STATE_SAVE_ALIGNMENT ++ ++#define USE_XSAVEC ++#define STATE_SAVE_ALIGNMENT 64 ++#define _dl_runtime_resolve _dl_runtime_resolve_xsavec + #include "dl-trampoline.h" ++#undef _dl_runtime_resolve ++#undef USE_XSAVEC ++#undef STATE_SAVE_ALIGNMENT +diff --git a/sysdeps/x86_64/dl-trampoline.h b/sysdeps/x86_64/dl-trampoline.h +index b27fa06974..9ddaafee17 100644 +--- a/sysdeps/x86_64/dl-trampoline.h ++++ b/sysdeps/x86_64/dl-trampoline.h +@@ -16,139 +16,47 @@ + License along with the GNU C Library; if not, see + . */ + +-#undef REGISTER_SAVE_AREA_RAW +-#ifdef __ILP32__ +-/* X32 saves RCX, RDX, RSI, RDI, R8 and R9 plus RAX as well as VEC0 to +- VEC7. */ +-# define REGISTER_SAVE_AREA_RAW (8 * 7 + VEC_SIZE * 8) +-#else +-/* X86-64 saves RCX, RDX, RSI, RDI, R8 and R9 plus RAX as well as +- BND0, BND1, BND2, BND3 and VEC0 to VEC7. */ +-# define REGISTER_SAVE_AREA_RAW (8 * 7 + 16 * 4 + VEC_SIZE * 8) +-#endif ++ .text ++#ifdef _dl_runtime_resolve + +-#undef REGISTER_SAVE_AREA +-#undef LOCAL_STORAGE_AREA +-#undef BASE +-#if DL_RUNTIME_RESOLVE_REALIGN_STACK +-# define REGISTER_SAVE_AREA (REGISTER_SAVE_AREA_RAW + 8) +-/* Local stack area before jumping to function address: RBX. */ +-# define LOCAL_STORAGE_AREA 8 +-# define BASE rbx +-# if (REGISTER_SAVE_AREA % VEC_SIZE) != 0 +-# error REGISTER_SAVE_AREA must be multples of VEC_SIZE +-# endif +-#else +-# define REGISTER_SAVE_AREA REGISTER_SAVE_AREA_RAW +-/* Local stack area before jumping to function address: All saved +- registers. */ +-# define LOCAL_STORAGE_AREA REGISTER_SAVE_AREA +-# define BASE rsp +-# if (REGISTER_SAVE_AREA % 16) != 8 +-# error REGISTER_SAVE_AREA must be odd multples of 8 ++# undef REGISTER_SAVE_AREA ++# undef LOCAL_STORAGE_AREA ++# undef BASE ++ ++# if (STATE_SAVE_ALIGNMENT % 16) != 0 ++# error STATE_SAVE_ALIGNMENT must be multples of 16 + # endif +-#endif + +- .text +-#ifdef _dl_runtime_resolve_opt +-/* Use the smallest vector registers to preserve the full YMM/ZMM +- registers to avoid SSE transition penalty. */ +- +-# if VEC_SIZE == 32 +-/* Check if the upper 128 bits in %ymm0 - %ymm7 registers are non-zero +- and preserve %xmm0 - %xmm7 registers with the zero upper bits. Since +- there is no SSE transition penalty on AVX512 processors which don't +- support XGETBV with ECX == 1, _dl_runtime_resolve_avx512_slow isn't +- provided. */ +- .globl _dl_runtime_resolve_avx_slow +- .hidden _dl_runtime_resolve_avx_slow +- .type _dl_runtime_resolve_avx_slow, @function +- .align 16 +-_dl_runtime_resolve_avx_slow: +- cfi_startproc +- cfi_adjust_cfa_offset(16) # Incorporate PLT +- vorpd %ymm0, %ymm1, %ymm8 +- vorpd %ymm2, %ymm3, %ymm9 +- vorpd %ymm4, %ymm5, %ymm10 +- vorpd %ymm6, %ymm7, %ymm11 +- vorpd %ymm8, %ymm9, %ymm9 +- vorpd %ymm10, %ymm11, %ymm10 +- vpcmpeqd %xmm8, %xmm8, %xmm8 +- vorpd %ymm9, %ymm10, %ymm10 +- vptest %ymm10, %ymm8 +- # Preserve %ymm0 - %ymm7 registers if the upper 128 bits of any +- # %ymm0 - %ymm7 registers aren't zero. +- PRESERVE_BND_REGS_PREFIX +- jnc _dl_runtime_resolve_avx +- # Use vzeroupper to avoid SSE transition penalty. +- vzeroupper +- # Preserve %xmm0 - %xmm7 registers with the zero upper 128 bits +- # when the upper 128 bits of %ymm0 - %ymm7 registers are zero. +- PRESERVE_BND_REGS_PREFIX +- jmp _dl_runtime_resolve_sse_vex +- cfi_adjust_cfa_offset(-16) # Restore PLT adjustment +- cfi_endproc +- .size _dl_runtime_resolve_avx_slow, .-_dl_runtime_resolve_avx_slow ++# if (STATE_SAVE_OFFSET % STATE_SAVE_ALIGNMENT) != 0 ++# error STATE_SAVE_OFFSET must be multples of STATE_SAVE_ALIGNMENT + # endif + +-/* Use XGETBV with ECX == 1 to check which bits in vector registers are +- non-zero and only preserve the non-zero lower bits with zero upper +- bits. */ +- .globl _dl_runtime_resolve_opt +- .hidden _dl_runtime_resolve_opt +- .type _dl_runtime_resolve_opt, @function +- .align 16 +-_dl_runtime_resolve_opt: +- cfi_startproc +- cfi_adjust_cfa_offset(16) # Incorporate PLT +- pushq %rax +- cfi_adjust_cfa_offset(8) +- cfi_rel_offset(%rax, 0) +- pushq %rcx +- cfi_adjust_cfa_offset(8) +- cfi_rel_offset(%rcx, 0) +- pushq %rdx +- cfi_adjust_cfa_offset(8) +- cfi_rel_offset(%rdx, 0) +- movl $1, %ecx +- xgetbv +- movl %eax, %r11d +- popq %rdx +- cfi_adjust_cfa_offset(-8) +- cfi_restore (%rdx) +- popq %rcx +- cfi_adjust_cfa_offset(-8) +- cfi_restore (%rcx) +- popq %rax +- cfi_adjust_cfa_offset(-8) +- cfi_restore (%rax) +-# if VEC_SIZE == 32 +- # For YMM registers, check if YMM state is in use. +- andl $bit_YMM_state, %r11d +- # Preserve %xmm0 - %xmm7 registers with the zero upper 128 bits if +- # YMM state isn't in use. +- PRESERVE_BND_REGS_PREFIX +- jz _dl_runtime_resolve_sse_vex +-# elif VEC_SIZE == 64 +- # For ZMM registers, check if YMM state and ZMM state are in +- # use. +- andl $(bit_YMM_state | bit_ZMM0_15_state), %r11d +- cmpl $bit_YMM_state, %r11d +- # Preserve %xmm0 - %xmm7 registers with the zero upper 384 bits if +- # neither YMM state nor ZMM state are in use. +- PRESERVE_BND_REGS_PREFIX +- jl _dl_runtime_resolve_sse_vex +- # Preserve %ymm0 - %ymm7 registers with the zero upper 256 bits if +- # ZMM state isn't in use. +- PRESERVE_BND_REGS_PREFIX +- je _dl_runtime_resolve_avx ++# if DL_RUNTIME_RESOLVE_REALIGN_STACK ++/* Local stack area before jumping to function address: RBX. */ ++# define LOCAL_STORAGE_AREA 8 ++# define BASE rbx ++# ifdef USE_FXSAVE ++/* Use fxsave to save XMM registers. */ ++# define REGISTER_SAVE_AREA (512 + STATE_SAVE_OFFSET) ++# if (REGISTER_SAVE_AREA % 16) != 0 ++# error REGISTER_SAVE_AREA must be multples of 16 ++# endif ++# endif + # else +-# error Unsupported VEC_SIZE! ++# ifndef USE_FXSAVE ++# error USE_FXSAVE must be defined ++# endif ++/* Use fxsave to save XMM registers. */ ++# define REGISTER_SAVE_AREA (512 + STATE_SAVE_OFFSET + 8) ++/* Local stack area before jumping to function address: All saved ++ registers. */ ++# define LOCAL_STORAGE_AREA REGISTER_SAVE_AREA ++# define BASE rsp ++# if (REGISTER_SAVE_AREA % 16) != 8 ++# error REGISTER_SAVE_AREA must be odd multples of 8 ++# endif + # endif +- cfi_adjust_cfa_offset(-16) # Restore PLT adjustment +- cfi_endproc +- .size _dl_runtime_resolve_opt, .-_dl_runtime_resolve_opt +-#endif ++ + .globl _dl_runtime_resolve + .hidden _dl_runtime_resolve + .type _dl_runtime_resolve, @function +@@ -156,21 +64,30 @@ _dl_runtime_resolve_opt: + cfi_startproc + _dl_runtime_resolve: + cfi_adjust_cfa_offset(16) # Incorporate PLT +-#if DL_RUNTIME_RESOLVE_REALIGN_STACK +-# if LOCAL_STORAGE_AREA != 8 +-# error LOCAL_STORAGE_AREA must be 8 +-# endif ++# if DL_RUNTIME_RESOLVE_REALIGN_STACK ++# if LOCAL_STORAGE_AREA != 8 ++# error LOCAL_STORAGE_AREA must be 8 ++# endif + pushq %rbx # push subtracts stack by 8. + cfi_adjust_cfa_offset(8) + cfi_rel_offset(%rbx, 0) + mov %RSP_LP, %RBX_LP + cfi_def_cfa_register(%rbx) +- and $-VEC_SIZE, %RSP_LP +-#endif ++ and $-STATE_SAVE_ALIGNMENT, %RSP_LP ++# endif ++# ifdef REGISTER_SAVE_AREA + sub $REGISTER_SAVE_AREA, %RSP_LP +-#if !DL_RUNTIME_RESOLVE_REALIGN_STACK ++# if !DL_RUNTIME_RESOLVE_REALIGN_STACK + cfi_adjust_cfa_offset(REGISTER_SAVE_AREA) +-#endif ++# endif ++# else ++ # Allocate stack space of the required size to save the state. ++# if IS_IN (rtld) ++ sub _rtld_local_ro+RTLD_GLOBAL_RO_DL_X86_CPU_FEATURES_OFFSET+XSAVE_STATE_SIZE_OFFSET(%rip), %RSP_LP ++# else ++ sub _dl_x86_cpu_features+XSAVE_STATE_SIZE_OFFSET(%rip), %RSP_LP ++# endif ++# endif + # Preserve registers otherwise clobbered. + movq %rax, REGISTER_SAVE_RAX(%rsp) + movq %rcx, REGISTER_SAVE_RCX(%rsp) +@@ -179,59 +96,42 @@ _dl_runtime_resolve: + movq %rdi, REGISTER_SAVE_RDI(%rsp) + movq %r8, REGISTER_SAVE_R8(%rsp) + movq %r9, REGISTER_SAVE_R9(%rsp) +- VMOV %VEC(0), (REGISTER_SAVE_VEC_OFF)(%rsp) +- VMOV %VEC(1), (REGISTER_SAVE_VEC_OFF + VEC_SIZE)(%rsp) +- VMOV %VEC(2), (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 2)(%rsp) +- VMOV %VEC(3), (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 3)(%rsp) +- VMOV %VEC(4), (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 4)(%rsp) +- VMOV %VEC(5), (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 5)(%rsp) +- VMOV %VEC(6), (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 6)(%rsp) +- VMOV %VEC(7), (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 7)(%rsp) +-#ifndef __ILP32__ +- # We also have to preserve bound registers. These are nops if +- # Intel MPX isn't available or disabled. +-# ifdef HAVE_MPX_SUPPORT +- bndmov %bnd0, REGISTER_SAVE_BND0(%rsp) +- bndmov %bnd1, REGISTER_SAVE_BND1(%rsp) +- bndmov %bnd2, REGISTER_SAVE_BND2(%rsp) +- bndmov %bnd3, REGISTER_SAVE_BND3(%rsp) ++# ifdef USE_FXSAVE ++ fxsave STATE_SAVE_OFFSET(%rsp) + # else +-# if REGISTER_SAVE_BND0 == 0 +- .byte 0x66,0x0f,0x1b,0x04,0x24 ++ movl $STATE_SAVE_MASK, %eax ++ xorl %edx, %edx ++ # Clear the XSAVE Header. ++# ifdef USE_XSAVE ++ movq %rdx, (STATE_SAVE_OFFSET + 512)(%rsp) ++ movq %rdx, (STATE_SAVE_OFFSET + 512 + 8)(%rsp) ++# endif ++ movq %rdx, (STATE_SAVE_OFFSET + 512 + 8 * 2)(%rsp) ++ movq %rdx, (STATE_SAVE_OFFSET + 512 + 8 * 3)(%rsp) ++ movq %rdx, (STATE_SAVE_OFFSET + 512 + 8 * 4)(%rsp) ++ movq %rdx, (STATE_SAVE_OFFSET + 512 + 8 * 5)(%rsp) ++ movq %rdx, (STATE_SAVE_OFFSET + 512 + 8 * 6)(%rsp) ++ movq %rdx, (STATE_SAVE_OFFSET + 512 + 8 * 7)(%rsp) ++# ifdef USE_XSAVE ++ xsave STATE_SAVE_OFFSET(%rsp) + # else +- .byte 0x66,0x0f,0x1b,0x44,0x24,REGISTER_SAVE_BND0 ++ xsavec STATE_SAVE_OFFSET(%rsp) + # endif +- .byte 0x66,0x0f,0x1b,0x4c,0x24,REGISTER_SAVE_BND1 +- .byte 0x66,0x0f,0x1b,0x54,0x24,REGISTER_SAVE_BND2 +- .byte 0x66,0x0f,0x1b,0x5c,0x24,REGISTER_SAVE_BND3 + # endif +-#endif + # Copy args pushed by PLT in register. + # %rdi: link_map, %rsi: reloc_index + mov (LOCAL_STORAGE_AREA + 8)(%BASE), %RSI_LP + mov LOCAL_STORAGE_AREA(%BASE), %RDI_LP + call _dl_fixup # Call resolver. + mov %RAX_LP, %R11_LP # Save return value +-#ifndef __ILP32__ +- # Restore bound registers. These are nops if Intel MPX isn't +- # avaiable or disabled. +-# ifdef HAVE_MPX_SUPPORT +- bndmov REGISTER_SAVE_BND3(%rsp), %bnd3 +- bndmov REGISTER_SAVE_BND2(%rsp), %bnd2 +- bndmov REGISTER_SAVE_BND1(%rsp), %bnd1 +- bndmov REGISTER_SAVE_BND0(%rsp), %bnd0 ++ # Get register content back. ++# ifdef USE_FXSAVE ++ fxrstor STATE_SAVE_OFFSET(%rsp) + # else +- .byte 0x66,0x0f,0x1a,0x5c,0x24,REGISTER_SAVE_BND3 +- .byte 0x66,0x0f,0x1a,0x54,0x24,REGISTER_SAVE_BND2 +- .byte 0x66,0x0f,0x1a,0x4c,0x24,REGISTER_SAVE_BND1 +-# if REGISTER_SAVE_BND0 == 0 +- .byte 0x66,0x0f,0x1a,0x04,0x24 +-# else +- .byte 0x66,0x0f,0x1a,0x44,0x24,REGISTER_SAVE_BND0 +-# endif ++ movl $STATE_SAVE_MASK, %eax ++ xorl %edx, %edx ++ xrstor STATE_SAVE_OFFSET(%rsp) + # endif +-#endif +- # Get register content back. + movq REGISTER_SAVE_R9(%rsp), %r9 + movq REGISTER_SAVE_R8(%rsp), %r8 + movq REGISTER_SAVE_RDI(%rsp), %rdi +@@ -239,20 +139,12 @@ _dl_runtime_resolve: + movq REGISTER_SAVE_RDX(%rsp), %rdx + movq REGISTER_SAVE_RCX(%rsp), %rcx + movq REGISTER_SAVE_RAX(%rsp), %rax +- VMOV (REGISTER_SAVE_VEC_OFF)(%rsp), %VEC(0) +- VMOV (REGISTER_SAVE_VEC_OFF + VEC_SIZE)(%rsp), %VEC(1) +- VMOV (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 2)(%rsp), %VEC(2) +- VMOV (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 3)(%rsp), %VEC(3) +- VMOV (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 4)(%rsp), %VEC(4) +- VMOV (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 5)(%rsp), %VEC(5) +- VMOV (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 6)(%rsp), %VEC(6) +- VMOV (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 7)(%rsp), %VEC(7) +-#if DL_RUNTIME_RESOLVE_REALIGN_STACK ++# if DL_RUNTIME_RESOLVE_REALIGN_STACK + mov %RBX_LP, %RSP_LP + cfi_def_cfa_register(%rsp) + movq (%rsp), %rbx + cfi_restore(%rbx) +-#endif ++# endif + # Adjust stack(PLT did 2 pushes) + add $(LOCAL_STORAGE_AREA + 16), %RSP_LP + cfi_adjust_cfa_offset(-(LOCAL_STORAGE_AREA + 16)) +@@ -261,11 +153,9 @@ _dl_runtime_resolve: + jmp *%r11 # Jump to function address. + cfi_endproc + .size _dl_runtime_resolve, .-_dl_runtime_resolve ++#endif + + +-/* To preserve %xmm0 - %xmm7 registers, dl-trampoline.h is included +- twice, for _dl_runtime_resolve_sse and _dl_runtime_resolve_sse_vex. +- But we don't need another _dl_runtime_profile for XMM registers. */ + #if !defined PROF && defined _dl_runtime_profile + # if (LR_VECTOR_OFFSET % VEC_SIZE) != 0 + # error LR_VECTOR_OFFSET must be multples of VEC_SIZE +diff --git a/sysdeps/x86_64/localplt.data b/sysdeps/x86_64/localplt.data +index 014a9f4554..a1840cff31 100644 +--- a/sysdeps/x86_64/localplt.data ++++ b/sysdeps/x86_64/localplt.data +@@ -8,7 +8,7 @@ libc.so: free + RELA R_X86_64_GLOB_DAT + libc.so: malloc + RELA R_X86_64_GLOB_DAT + libc.so: memalign + RELA R_X86_64_GLOB_DAT + libc.so: realloc + RELA R_X86_64_GLOB_DAT +-libm.so: matherr ++libm.so: matherr + RELA R_X86_64_GLOB_DAT + # The main malloc is interposed into the dynamic linker, for + # allocations after the initial link (when dlopen is used). + ld.so: malloc + RELA R_X86_64_GLOB_DAT +diff --git a/sysdeps/x86_64/mempcpy_chk.S b/sysdeps/x86_64/mempcpy_chk.S +index f8a9260e6e..f912291576 100644 +--- a/sysdeps/x86_64/mempcpy_chk.S ++++ b/sysdeps/x86_64/mempcpy_chk.S +@@ -19,7 +19,7 @@ + #include + #include "asm-syntax.h" + +-#ifndef PIC ++#ifndef SHARED + /* For libc.so this is defined in memcpy.S. + For libc.a, this is a separate source to avoid + mempcpy bringing in __chk_fail and all routines +diff --git a/sysdeps/x86_64/multiarch/memcpy.S b/sysdeps/x86_64/multiarch/memcpy.S +index 1f83ee3e84..af2770397c 100644 +--- a/sysdeps/x86_64/multiarch/memcpy.S ++++ b/sysdeps/x86_64/multiarch/memcpy.S +@@ -32,6 +32,8 @@ ENTRY(__new_memcpy) + lea __memcpy_erms(%rip), %RAX_LP + HAS_ARCH_FEATURE (Prefer_ERMS) + jnz 2f ++ HAS_ARCH_FEATURE (Prefer_No_AVX512) ++ jnz 1f + HAS_ARCH_FEATURE (AVX512F_Usable) + jz 1f + lea __memcpy_avx512_no_vzeroupper(%rip), %RAX_LP +diff --git a/sysdeps/x86_64/multiarch/memcpy_chk.S b/sysdeps/x86_64/multiarch/memcpy_chk.S +index 54923420f1..8737fb9755 100644 +--- a/sysdeps/x86_64/multiarch/memcpy_chk.S ++++ b/sysdeps/x86_64/multiarch/memcpy_chk.S +@@ -30,6 +30,8 @@ + ENTRY(__memcpy_chk) + .type __memcpy_chk, @gnu_indirect_function + LOAD_RTLD_GLOBAL_RO_RDX ++ HAS_ARCH_FEATURE (Prefer_No_AVX512) ++ jnz 1f + HAS_ARCH_FEATURE (AVX512F_Usable) + jz 1f + lea __memcpy_chk_avx512_no_vzeroupper(%rip), %RAX_LP +diff --git a/sysdeps/x86_64/multiarch/memmove.S b/sysdeps/x86_64/multiarch/memmove.S +index 2021bfc30c..8c534e83e0 100644 +--- a/sysdeps/x86_64/multiarch/memmove.S ++++ b/sysdeps/x86_64/multiarch/memmove.S +@@ -30,6 +30,8 @@ ENTRY(__libc_memmove) + lea __memmove_erms(%rip), %RAX_LP + HAS_ARCH_FEATURE (Prefer_ERMS) + jnz 2f ++ HAS_ARCH_FEATURE (Prefer_No_AVX512) ++ jnz 1f + HAS_ARCH_FEATURE (AVX512F_Usable) + jz 1f + lea __memmove_avx512_no_vzeroupper(%rip), %RAX_LP +diff --git a/sysdeps/x86_64/multiarch/memmove_chk.S b/sysdeps/x86_64/multiarch/memmove_chk.S +index 8a252adcae..7870dd0247 100644 +--- a/sysdeps/x86_64/multiarch/memmove_chk.S ++++ b/sysdeps/x86_64/multiarch/memmove_chk.S +@@ -29,6 +29,8 @@ + ENTRY(__memmove_chk) + .type __memmove_chk, @gnu_indirect_function + LOAD_RTLD_GLOBAL_RO_RDX ++ HAS_ARCH_FEATURE (Prefer_No_AVX512) ++ jnz 1f + HAS_ARCH_FEATURE (AVX512F_Usable) + jz 1f + lea __memmove_chk_avx512_no_vzeroupper(%rip), %RAX_LP +diff --git a/sysdeps/x86_64/multiarch/mempcpy.S b/sysdeps/x86_64/multiarch/mempcpy.S +index 79c840d075..b8b2b28094 100644 +--- a/sysdeps/x86_64/multiarch/mempcpy.S ++++ b/sysdeps/x86_64/multiarch/mempcpy.S +@@ -32,6 +32,8 @@ ENTRY(__mempcpy) + lea __mempcpy_erms(%rip), %RAX_LP + HAS_ARCH_FEATURE (Prefer_ERMS) + jnz 2f ++ HAS_ARCH_FEATURE (Prefer_No_AVX512) ++ jnz 1f + HAS_ARCH_FEATURE (AVX512F_Usable) + jz 1f + lea __mempcpy_avx512_no_vzeroupper(%rip), %RAX_LP +diff --git a/sysdeps/x86_64/multiarch/mempcpy_chk.S b/sysdeps/x86_64/multiarch/mempcpy_chk.S +index 6927962e81..072b22c49f 100644 +--- a/sysdeps/x86_64/multiarch/mempcpy_chk.S ++++ b/sysdeps/x86_64/multiarch/mempcpy_chk.S +@@ -30,6 +30,8 @@ + ENTRY(__mempcpy_chk) + .type __mempcpy_chk, @gnu_indirect_function + LOAD_RTLD_GLOBAL_RO_RDX ++ HAS_ARCH_FEATURE (Prefer_No_AVX512) ++ jnz 1f + HAS_ARCH_FEATURE (AVX512F_Usable) + jz 1f + lea __mempcpy_chk_avx512_no_vzeroupper(%rip), %RAX_LP +diff --git a/sysdeps/x86_64/multiarch/memset.S b/sysdeps/x86_64/multiarch/memset.S +index c958b2f49f..9d33118cf8 100644 +--- a/sysdeps/x86_64/multiarch/memset.S ++++ b/sysdeps/x86_64/multiarch/memset.S +@@ -41,6 +41,8 @@ ENTRY(memset) + jnz L(AVX512F) + lea __memset_avx2_unaligned(%rip), %RAX_LP + L(AVX512F): ++ HAS_ARCH_FEATURE (Prefer_No_AVX512) ++ jnz 2f + HAS_ARCH_FEATURE (AVX512F_Usable) + jz 2f + lea __memset_avx512_no_vzeroupper(%rip), %RAX_LP +diff --git a/sysdeps/x86_64/multiarch/memset_chk.S b/sysdeps/x86_64/multiarch/memset_chk.S +index 79eaa37bb6..7e08311cdf 100644 +--- a/sysdeps/x86_64/multiarch/memset_chk.S ++++ b/sysdeps/x86_64/multiarch/memset_chk.S +@@ -38,6 +38,8 @@ ENTRY(__memset_chk) + jnz L(AVX512F) + lea __memset_chk_avx2_unaligned(%rip), %RAX_LP + L(AVX512F): ++ HAS_ARCH_FEATURE (Prefer_No_AVX512) ++ jnz 2f + HAS_ARCH_FEATURE (AVX512F_Usable) + jz 2f + lea __memset_chk_avx512_no_vzeroupper(%rip), %RAX_LP +diff --git a/sysdeps/x86_64/rtld-offsets.sym b/sysdeps/x86_64/rtld-offsets.sym +new file mode 100644 +index 0000000000..fd41b51521 +--- /dev/null ++++ b/sysdeps/x86_64/rtld-offsets.sym +@@ -0,0 +1,6 @@ ++#define SHARED ++#include ++ ++-- ++ ++GL_TLS_GENERATION_OFFSET offsetof (struct rtld_global, _dl_tls_generation) +diff --git a/sysdeps/x86_64/tls_get_addr.S b/sysdeps/x86_64/tls_get_addr.S +new file mode 100644 +index 0000000000..9d38fb3be5 +--- /dev/null ++++ b/sysdeps/x86_64/tls_get_addr.S +@@ -0,0 +1,61 @@ ++/* Stack-aligning implementation of __tls_get_addr. x86-64 version. ++ Copyright (C) 2017 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 ++ . */ ++ ++#ifdef SHARED ++ ++# include ++# include "tlsdesc.h" ++# include "rtld-offsets.h" ++ ++/* See __tls_get_addr and __tls_get_addr_slow in dl-tls.c. This function ++ call __tls_get_addr_slow on both slow paths. It realigns the stack ++ before the call to work around GCC PR58066. */ ++ ++ENTRY (__tls_get_addr) ++ mov %fs:DTV_OFFSET, %RDX_LP ++ mov GL_TLS_GENERATION_OFFSET+_rtld_local(%rip), %RAX_LP ++ /* GL(dl_tls_generation) == dtv[0].counter */ ++ cmp %RAX_LP, (%rdx) ++ jne 1f ++ mov TI_MODULE_OFFSET(%rdi), %RAX_LP ++ /* dtv[ti->ti_module] */ ++# ifdef __LP64__ ++ salq $4, %rax ++ movq (%rdx,%rax), %rax ++# else ++ movl (%rdx,%rax, 8), %eax ++# endif ++ cmp $-1, %RAX_LP ++ je 1f ++ add TI_OFFSET_OFFSET(%rdi), %RAX_LP ++ ret ++1: ++ /* On the slow path, align the stack. */ ++ pushq %rbp ++ cfi_def_cfa_offset (16) ++ cfi_offset (%rbp, -16) ++ mov %RSP_LP, %RBP_LP ++ cfi_def_cfa_register (%rbp) ++ and $-16, %RSP_LP ++ call __tls_get_addr_slow ++ mov %RBP_LP, %RSP_LP ++ popq %rbp ++ cfi_def_cfa (%rsp, 8) ++ ret ++END (__tls_get_addr) ++#endif /* SHARED */ +diff --git a/sysdeps/x86_64/tlsdesc.sym b/sysdeps/x86_64/tlsdesc.sym +index 33854975d0..fc897ab4b5 100644 +--- a/sysdeps/x86_64/tlsdesc.sym ++++ b/sysdeps/x86_64/tlsdesc.sym +@@ -15,3 +15,6 @@ TLSDESC_ARG offsetof(struct tlsdesc, arg) + TLSDESC_GEN_COUNT offsetof(struct tlsdesc_dynamic_arg, gen_count) + TLSDESC_MODID offsetof(struct tlsdesc_dynamic_arg, tlsinfo.ti_module) + TLSDESC_MODOFF offsetof(struct tlsdesc_dynamic_arg, tlsinfo.ti_offset) ++ ++TI_MODULE_OFFSET offsetof(tls_index, ti_module) ++TI_OFFSET_OFFSET offsetof(tls_index, ti_offset) +diff --git a/sysdeps/x86_64/tst-avx-aux.c b/sysdeps/x86_64/tst-avx-aux.c +new file mode 100644 +index 0000000000..e3807de7bb +--- /dev/null ++++ b/sysdeps/x86_64/tst-avx-aux.c +@@ -0,0 +1,47 @@ ++/* Test case for preserved AVX registers in dynamic linker, -mavx part. ++ Copyright (C) 2017 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 ++ . */ ++ ++#include ++#include ++#include ++ ++int ++tst_avx_aux (void) ++{ ++#ifdef __AVX__ ++ extern __m256i avx_test (__m256i, __m256i, __m256i, __m256i, ++ __m256i, __m256i, __m256i, __m256i); ++ ++ __m256i ymm0 = _mm256_set1_epi32 (0); ++ __m256i ymm1 = _mm256_set1_epi32 (1); ++ __m256i ymm2 = _mm256_set1_epi32 (2); ++ __m256i ymm3 = _mm256_set1_epi32 (3); ++ __m256i ymm4 = _mm256_set1_epi32 (4); ++ __m256i ymm5 = _mm256_set1_epi32 (5); ++ __m256i ymm6 = _mm256_set1_epi32 (6); ++ __m256i ymm7 = _mm256_set1_epi32 (7); ++ __m256i ret = avx_test (ymm0, ymm1, ymm2, ymm3, ++ ymm4, ymm5, ymm6, ymm7); ++ ymm0 = _mm256_set1_epi32 (0x12349876); ++ if (memcmp (&ymm0, &ret, sizeof (ret))) ++ abort (); ++ return 0; ++#else /* __AVX__ */ ++ return 77; ++#endif /* __AVX__ */ ++} +diff --git a/sysdeps/x86_64/tst-avx.c b/sysdeps/x86_64/tst-avx.c +new file mode 100644 +index 0000000000..ec2e3a79ff +--- /dev/null ++++ b/sysdeps/x86_64/tst-avx.c +@@ -0,0 +1,49 @@ ++/* Test case for preserved AVX registers in dynamic linker. ++ Copyright (C) 2017 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 ++ . */ ++ ++#include ++ ++int tst_avx_aux (void); ++ ++static int ++avx_enabled (void) ++{ ++ unsigned int eax, ebx, ecx, edx; ++ ++ if (__get_cpuid (1, &eax, &ebx, &ecx, &edx) == 0 ++ || (ecx & (bit_AVX | bit_OSXSAVE)) != (bit_AVX | bit_OSXSAVE)) ++ return 0; ++ ++ /* Check the OS has AVX and SSE saving enabled. */ ++ asm ("xgetbv" : "=a" (eax), "=d" (edx) : "c" (0)); ++ ++ return (eax & 6) == 6; ++} ++ ++static int ++do_test (void) ++{ ++ /* Run AVX test only if AVX is supported. */ ++ if (avx_enabled ()) ++ return tst_avx_aux (); ++ else ++ return 77; ++} ++ ++#define TEST_FUNCTION do_test () ++#include "../../test-skeleton.c" +diff --git a/sysdeps/x86_64/tst-avx512-aux.c b/sysdeps/x86_64/tst-avx512-aux.c +new file mode 100644 +index 0000000000..6cebc523f2 +--- /dev/null ++++ b/sysdeps/x86_64/tst-avx512-aux.c +@@ -0,0 +1,48 @@ ++/* Test case for preserved AVX512 registers in dynamic linker, ++ -mavx512 part. ++ Copyright (C) 2017 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 ++ . */ ++ ++#include ++#include ++#include ++ ++int ++tst_avx512_aux (void) ++{ ++#ifdef __AVX512F__ ++ extern __m512i avx512_test (__m512i, __m512i, __m512i, __m512i, ++ __m512i, __m512i, __m512i, __m512i); ++ ++ __m512i zmm0 = _mm512_set1_epi32 (0); ++ __m512i zmm1 = _mm512_set1_epi32 (1); ++ __m512i zmm2 = _mm512_set1_epi32 (2); ++ __m512i zmm3 = _mm512_set1_epi32 (3); ++ __m512i zmm4 = _mm512_set1_epi32 (4); ++ __m512i zmm5 = _mm512_set1_epi32 (5); ++ __m512i zmm6 = _mm512_set1_epi32 (6); ++ __m512i zmm7 = _mm512_set1_epi32 (7); ++ __m512i ret = avx512_test (zmm0, zmm1, zmm2, zmm3, ++ zmm4, zmm5, zmm6, zmm7); ++ zmm0 = _mm512_set1_epi32 (0x12349876); ++ if (memcmp (&zmm0, &ret, sizeof (ret))) ++ abort (); ++ return 0; ++#else /* __AVX512F__ */ ++ return 77; ++#endif /* __AVX512F__ */ ++} +diff --git a/sysdeps/x86_64/tst-avx512.c b/sysdeps/x86_64/tst-avx512.c +new file mode 100644 +index 0000000000..a8e42ef553 +--- /dev/null ++++ b/sysdeps/x86_64/tst-avx512.c +@@ -0,0 +1,57 @@ ++/* Test case for preserved AVX512 registers in dynamic linker. ++ Copyright (C) 2017 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 ++ . */ ++ ++#include ++ ++int tst_avx512_aux (void); ++ ++static int ++avx512_enabled (void) ++{ ++#ifdef bit_AVX512F ++ unsigned int eax, ebx, ecx, edx; ++ ++ if (__get_cpuid (1, &eax, &ebx, &ecx, &edx) == 0 ++ || (ecx & (bit_AVX | bit_OSXSAVE)) != (bit_AVX | bit_OSXSAVE)) ++ return 0; ++ ++ __cpuid_count (7, 0, eax, ebx, ecx, edx); ++ if (!(ebx & bit_AVX512F)) ++ return 0; ++ ++ asm ("xgetbv" : "=a" (eax), "=d" (edx) : "c" (0)); ++ ++ /* Verify that ZMM, YMM and XMM states are enabled. */ ++ return (eax & 0xe6) == 0xe6; ++#else ++ return 0; ++#endif ++} ++ ++static int ++do_test (void) ++{ ++ /* Run AVX512 test only if AVX512 is supported. */ ++ if (avx512_enabled ()) ++ return tst_avx512_aux (); ++ else ++ return 77; ++} ++ ++#define TEST_FUNCTION do_test () ++#include "../../test-skeleton.c" +diff --git a/sysdeps/x86_64/tst-avx512mod.c b/sysdeps/x86_64/tst-avx512mod.c +new file mode 100644 +index 0000000000..4cfb3a2c3d +--- /dev/null ++++ b/sysdeps/x86_64/tst-avx512mod.c +@@ -0,0 +1,48 @@ ++/* Test case for x86-64 preserved AVX512 registers in dynamic linker. */ ++ ++#ifdef __AVX512F__ ++#include ++#include ++#include ++ ++__m512i ++avx512_test (__m512i x0, __m512i x1, __m512i x2, __m512i x3, ++ __m512i x4, __m512i x5, __m512i x6, __m512i x7) ++{ ++ __m512i zmm; ++ ++ zmm = _mm512_set1_epi32 (0); ++ if (memcmp (&zmm, &x0, sizeof (zmm))) ++ abort (); ++ ++ zmm = _mm512_set1_epi32 (1); ++ if (memcmp (&zmm, &x1, sizeof (zmm))) ++ abort (); ++ ++ zmm = _mm512_set1_epi32 (2); ++ if (memcmp (&zmm, &x2, sizeof (zmm))) ++ abort (); ++ ++ zmm = _mm512_set1_epi32 (3); ++ if (memcmp (&zmm, &x3, sizeof (zmm))) ++ abort (); ++ ++ zmm = _mm512_set1_epi32 (4); ++ if (memcmp (&zmm, &x4, sizeof (zmm))) ++ abort (); ++ ++ zmm = _mm512_set1_epi32 (5); ++ if (memcmp (&zmm, &x5, sizeof (zmm))) ++ abort (); ++ ++ zmm = _mm512_set1_epi32 (6); ++ if (memcmp (&zmm, &x6, sizeof (zmm))) ++ abort (); ++ ++ zmm = _mm512_set1_epi32 (7); ++ if (memcmp (&zmm, &x7, sizeof (zmm))) ++ abort (); ++ ++ return _mm512_set1_epi32 (0x12349876); ++} ++#endif +diff --git a/sysdeps/x86_64/tst-avxmod.c b/sysdeps/x86_64/tst-avxmod.c +new file mode 100644 +index 0000000000..6e5b154997 +--- /dev/null ++++ b/sysdeps/x86_64/tst-avxmod.c +@@ -0,0 +1,48 @@ ++/* Test case for x86-64 preserved AVX registers in dynamic linker. */ ++ ++#ifdef __AVX__ ++#include ++#include ++#include ++ ++__m256i ++avx_test (__m256i x0, __m256i x1, __m256i x2, __m256i x3, ++ __m256i x4, __m256i x5, __m256i x6, __m256i x7) ++{ ++ __m256i ymm; ++ ++ ymm = _mm256_set1_epi32 (0); ++ if (memcmp (&ymm, &x0, sizeof (ymm))) ++ abort (); ++ ++ ymm = _mm256_set1_epi32 (1); ++ if (memcmp (&ymm, &x1, sizeof (ymm))) ++ abort (); ++ ++ ymm = _mm256_set1_epi32 (2); ++ if (memcmp (&ymm, &x2, sizeof (ymm))) ++ abort (); ++ ++ ymm = _mm256_set1_epi32 (3); ++ if (memcmp (&ymm, &x3, sizeof (ymm))) ++ abort (); ++ ++ ymm = _mm256_set1_epi32 (4); ++ if (memcmp (&ymm, &x4, sizeof (ymm))) ++ abort (); ++ ++ ymm = _mm256_set1_epi32 (5); ++ if (memcmp (&ymm, &x5, sizeof (ymm))) ++ abort (); ++ ++ ymm = _mm256_set1_epi32 (6); ++ if (memcmp (&ymm, &x6, sizeof (ymm))) ++ abort (); ++ ++ ymm = _mm256_set1_epi32 (7); ++ if (memcmp (&ymm, &x7, sizeof (ymm))) ++ abort (); ++ ++ return _mm256_set1_epi32 (0x12349876); ++} ++#endif +diff --git a/sysdeps/x86_64/tst-sse.c b/sysdeps/x86_64/tst-sse.c +new file mode 100644 +index 0000000000..dd1537cf27 +--- /dev/null ++++ b/sysdeps/x86_64/tst-sse.c +@@ -0,0 +1,46 @@ ++/* Test case for preserved SSE registers in dynamic linker. ++ Copyright (C) 2017 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 ++ . */ ++ ++#include ++#include ++#include ++ ++extern __m128i sse_test (__m128i, __m128i, __m128i, __m128i, ++ __m128i, __m128i, __m128i, __m128i); ++ ++static int ++do_test (void) ++{ ++ __m128i xmm0 = _mm_set1_epi32 (0); ++ __m128i xmm1 = _mm_set1_epi32 (1); ++ __m128i xmm2 = _mm_set1_epi32 (2); ++ __m128i xmm3 = _mm_set1_epi32 (3); ++ __m128i xmm4 = _mm_set1_epi32 (4); ++ __m128i xmm5 = _mm_set1_epi32 (5); ++ __m128i xmm6 = _mm_set1_epi32 (6); ++ __m128i xmm7 = _mm_set1_epi32 (7); ++ __m128i ret = sse_test (xmm0, xmm1, xmm2, xmm3, ++ xmm4, xmm5, xmm6, xmm7); ++ xmm0 = _mm_set1_epi32 (0x12349876); ++ if (memcmp (&xmm0, &ret, sizeof (ret))) ++ abort (); ++ return 0; ++} ++ ++#define TEST_FUNCTION do_test () ++#include "../../test-skeleton.c" +diff --git a/sysdeps/x86_64/tst-ssemod.c b/sysdeps/x86_64/tst-ssemod.c +new file mode 100644 +index 0000000000..907a64c69e +--- /dev/null ++++ b/sysdeps/x86_64/tst-ssemod.c +@@ -0,0 +1,46 @@ ++/* Test case for x86-64 preserved SSE registers in dynamic linker. */ ++ ++#include ++#include ++#include ++ ++__m128i ++sse_test (__m128i x0, __m128i x1, __m128i x2, __m128i x3, ++ __m128i x4, __m128i x5, __m128i x6, __m128i x7) ++{ ++ __m128i xmm; ++ ++ xmm = _mm_set1_epi32 (0); ++ if (memcmp (&xmm, &x0, sizeof (xmm))) ++ abort (); ++ ++ xmm = _mm_set1_epi32 (1); ++ if (memcmp (&xmm, &x1, sizeof (xmm))) ++ abort (); ++ ++ xmm = _mm_set1_epi32 (2); ++ if (memcmp (&xmm, &x2, sizeof (xmm))) ++ abort (); ++ ++ xmm = _mm_set1_epi32 (3); ++ if (memcmp (&xmm, &x3, sizeof (xmm))) ++ abort (); ++ ++ xmm = _mm_set1_epi32 (4); ++ if (memcmp (&xmm, &x4, sizeof (xmm))) ++ abort (); ++ ++ xmm = _mm_set1_epi32 (5); ++ if (memcmp (&xmm, &x5, sizeof (xmm))) ++ abort (); ++ ++ xmm = _mm_set1_epi32 (6); ++ if (memcmp (&xmm, &x6, sizeof (xmm))) ++ abort (); ++ ++ xmm = _mm_set1_epi32 (7); ++ if (memcmp (&xmm, &x7, sizeof (xmm))) ++ abort (); ++ ++ return _mm_set1_epi32 (0x12349876); ++}