From: Victor Martinez Date: Mon, 29 Jan 2018 23:21:11 +0000 (+0100) Subject: glibc: updated to 2.24-10 X-Git-Url: http://gitweb/?a=commitdiff_plain;h=e308f0f7f24c3fa181c7ad170057542860b83ea1;p=ports%2Fcore-arm.git glibc: updated to 2.24-10 --- diff --git a/glibc/.md5sum b/glibc/.md5sum index df9b2fe..da726e6 100644 --- a/glibc/.md5sum +++ b/glibc/.md5sum @@ -1,3 +1,4 @@ +4382c5b030a4995a9a4649dd735f6685 glibc-2.24-10.patch 97dc5517f92016f3d70d83e3162ad318 glibc-2.24.tar.xz 96156bec8e05de67384dc93e72bdc313 host.conf fbbc215a9b15ba4846f326cc88108057 hosts diff --git a/glibc/Pkgfile b/glibc/Pkgfile index b99bc98..beda9e1 100644 --- a/glibc/Pkgfile +++ b/glibc/Pkgfile @@ -6,10 +6,11 @@ name=glibc version=2.24 -release=3 -source=(http://ftp.gnu.org/gnu/glibc/glibc-$version.tar.xz \ - http://ftp.kernel.org/pub/linux/kernel/v4.x/linux-4.1.13.tar.xz \ - hosts resolv.conf nsswitch.conf host.conf ld.so.conf) +release=10 +source=(http://ftpmirror.gnu.org/gnu/glibc/glibc-2.24.tar.xz \ + http://www.kernel.org/pub/linux/kernel/v4.x/linux-4.1.13.tar.xz \ + hosts resolv.conf nsswitch.conf host.conf ld.so.conf \ + glibc-2.24-10.patch) build() { # install kernel headers @@ -18,9 +19,11 @@ build() { make ARCH=arm headers_check make ARCH=arm INSTALL_HDR_PATH=$PKG/usr headers_install + patch -p1 -d $SRC/$name-${version:0:4} -i $SRC/glibc-2.24-10.patch + mkdir $SRC/build cd $SRC/build - ../$name-$version/configure --prefix=/usr \ + ../$name-${version:0:4}/configure --prefix=/usr \ --build=arm-unknown-linux-gnueabihf \ --libexecdir=/usr/lib \ --with-headers=$PKG/usr/include \ @@ -33,6 +36,7 @@ build() { --enable-obsolete-rpc make + #make check make install_root=$PKG install install -m 0644 $SRC/$name-$version/nscd/nscd.conf $PKG/etc diff --git a/glibc/glibc-2.24-10.patch b/glibc/glibc-2.24-10.patch new file mode 100644 index 0000000..194691d --- /dev/null +++ b/glibc/glibc-2.24-10.patch @@ -0,0 +1,19308 @@ +diff --git a/ChangeLog b/ChangeLog +index c44c926094..cd499c5fe3 100644 +--- a/ChangeLog ++++ b/ChangeLog +@@ -1,3 +1,887 @@ ++2018-01-12 Dmitry V. Levin ++ ++ [BZ #22679] ++ CVE-2018-1000001 ++ * sysdeps/unix/sysv/linux/getcwd.c (__getcwd): Fall back to ++ generic_getcwd if the path returned by getcwd syscall is not absolute. ++ * io/tst-getcwd-abspath.c: New test. ++ * io/Makefile (tests): Add tst-getcwd-abspath. ++ ++ (gaih_inet): Likewise. ++ ++2017-12-30 Aurelien Jarno ++ ++ [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-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-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-10-19 H.J. Lu ++ ++ * sysdeps/x86_64/dl-trampoline.h (_dl_runtime_resolve): Don't ++ adjust CFA when allocating register save area on re-aligned ++ stack. ++ ++2016-12-21 Joseph Myers ++ ++ [BZ #20978] ++ * nis/nss_nisplus/nisplus-alias.c (_nss_nisplus_getaliasbyname_r): ++ Compare name == NULL, not name != NULL. ++ ++2016-11-08 Joseph Myers ++ ++ [BZ #20790] ++ * sunrpc/rpc_parse.c (get_prog_declaration): Increase buffer size ++ to MAXLINESIZE. ++ * sunrpc/bug20790.x: New file. ++ * sunrpc/Makefile [$(run-built-tests) = yes] (rpcgen-tests): New ++ variable. ++ [$(run-built-tests) = yes] (tests-special): Add $(rpcgen-tests). ++ [$(run-built-tests) = yes] ($(rpcgen-tests)): New rule. ++ ++2016-10-14 Steve Ellcey ++ ++ * sysdeps/ieee754/dbl-64/e_pow.c (checkint) Make conditions explicitly ++ boolean. ++ ++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-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-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-01-24 James Clarke ++ ++ * sysdeps/unix/sysv/linux/sh/sh3/ucontext_i.sym: Use new REG_R* ++ constants instead of the old R* ones. ++ * sysdeps/unix/sysv/linux/sh/sh4/ucontext_i.sym: Likewise. ++ * sysdeps/unix/sysv/linux/sh/sys/ucontext.h (NGPREG): Rename... ++ (NGREG): ... to this, to fit in with other architectures. ++ (gpregset_t): Use new NGREG macro. ++ [__USE_GNU]: Remove condition; all architectures other than tile ++ are unconditional. ++ (R*): Rename to REG_R*. ++ ++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. ++ ++2016-09-05 Aurelien Jarno ++ ++ * conform/Makefile (conformtest-header-tests): Pass -I. to $(PERL). ++ (linknamespace-symlists-tests): Likewise. ++ (linknamespace-header-tests): Likewise. ++ ++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. ++ ++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-02-01 Andreas Schwab ++ ++ * sysdeps/m68k/m680x0/m68020/atomic-machine.h ++ (__arch_compare_and_exchange_val_64_acq, atomic_exchange_acq) ++ (atomic_exchange_and_add, atomic_add): Add casts to 64 bit asm ++ operands. ++ ++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-06-07 Arjun Shankar ++ ++ * sysdeps/unix/sysv/linux/tst-clone2.c: Do not ++ include test-skeleton.c. ++ Include support/check.h and support/test-driver.c. ++ ++2016-11-24 Adhemerval Zanella ++ ++ * sysdeps/nptl/fork.c (__libc_fork): Remove pid cache setting. ++ * nptl/allocatestack.c (allocate_stack): Likewise. ++ (__reclaim_stacks): Likewise. ++ (setxid_signal_thread): Obtain pid through syscall. ++ * nptl/nptl-init.c (sigcancel_handler): Likewise. ++ (sighandle_setxid): Likewise. ++ * nptl/pthread_cancel.c (pthread_cancel): Likewise. ++ * sysdeps/unix/sysv/linux/pthread_kill.c (__pthread_kill): Likewise. ++ * sysdeps/unix/sysv/linux/pthread_sigqueue.c (pthread_sigqueue): ++ Likewise. ++ * sysdeps/unix/sysv/linux/createthread.c (create_thread): Likewise. ++ * sysdeps/unix/sysv/linux/raise.c (raise): Remove old behaviour ++ comment. ++ * sysdeps/unix/sysv/linux/getpid.c: Remove file. ++ * nptl/descr.h (struct pthread): Change comment about pid value. ++ * nptl/pthread_getattr_np.c (pthread_getattr_np): Remove thread ++ pid assert. ++ * sysdeps/unix/sysv/linux/pthread-pids.h (__pthread_initialize_pids): ++ Do not set pid value. ++ * nptl_db/td_ta_thr_iter.c (iterate_thread_list): Remove thread ++ pid cache check. ++ * nptl_db/td_thr_validate.c (td_thr_validate): Likewise. ++ * sysdeps/aarch64/nptl/tcb-offsets.sym: Remove pid offset. ++ * sysdeps/alpha/nptl/tcb-offsets.sym: Likewise. ++ * sysdeps/arm/nptl/tcb-offsets.sym: Likewise. ++ * sysdeps/hppa/nptl/tcb-offsets.sym: Likewise. ++ * sysdeps/i386/nptl/tcb-offsets.sym: Likewise. ++ * sysdeps/ia64/nptl/tcb-offsets.sym: Likewise. ++ * sysdeps/m68k/nptl/tcb-offsets.sym: Likewise. ++ * sysdeps/microblaze/nptl/tcb-offsets.sym: Likewise. ++ * sysdeps/mips/nptl/tcb-offsets.sym: Likewise. ++ * sysdeps/nios2/nptl/tcb-offsets.sym: Likewise. ++ * sysdeps/powerpc/nptl/tcb-offsets.sym: Likewise. ++ * sysdeps/s390/nptl/tcb-offsets.sym: Likewise. ++ * sysdeps/sh/nptl/tcb-offsets.sym: Likewise. ++ * sysdeps/sparc/nptl/tcb-offsets.sym: Likewise. ++ * sysdeps/tile/nptl/tcb-offsets.sym: Likewise. ++ * sysdeps/x86_64/nptl/tcb-offsets.sym: Likewise. ++ * sysdeps/unix/sysv/linux/aarch64/clone.S: Remove pid and tid caching. ++ * sysdeps/unix/sysv/linux/alpha/clone.S: Likewise. ++ * sysdeps/unix/sysv/linux/arm/clone.S: Likewise. ++ * sysdeps/unix/sysv/linux/hppa/clone.S: Likewise. ++ * sysdeps/unix/sysv/linux/i386/clone.S: Likewise. ++ * sysdeps/unix/sysv/linux/ia64/clone2.S: Likewise. ++ * sysdeps/unix/sysv/linux/mips/clone.S: Likewise. ++ * sysdeps/unix/sysv/linux/nios2/clone.S: Likewise. ++ * sysdeps/unix/sysv/linux/powerpc/powerpc32/clone.S: Likewise. ++ * sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S: Likewise. ++ * sysdeps/unix/sysv/linux/s390/s390-32/clone.S: Likewise. ++ * sysdeps/unix/sysv/linux/s390/s390-64/clone.S: Likewise. ++ * sysdeps/unix/sysv/linux/sh/clone.S: Likewise. ++ * sysdeps/unix/sysv/linux/sparc/sparc32/clone.S: Likewise. ++ * sysdeps/unix/sysv/linux/sparc/sparc64/clone.S: Likewise. ++ * sysdeps/unix/sysv/linux/tile/clone.S: Likewise. ++ * sysdeps/unix/sysv/linux/x86_64/clone.S: Likewise. ++ * sysdeps/unix/sysv/linux/aarch64/vfork.S: Remove pid set and reset. ++ * sysdeps/unix/sysv/linux/alpha/vfork.S: Likewise. ++ * sysdeps/unix/sysv/linux/arm/vfork.S: Likewise. ++ * sysdeps/unix/sysv/linux/i386/vfork.S: Likewise. ++ * sysdeps/unix/sysv/linux/ia64/vfork.S: Likewise. ++ * sysdeps/unix/sysv/linux/m68k/clone.S: Likewise. ++ * sysdeps/unix/sysv/linux/m68k/vfork.S: Likewise. ++ * sysdeps/unix/sysv/linux/mips/vfork.S: Likewise. ++ * sysdeps/unix/sysv/linux/nios2/vfork.S: Likewise. ++ * sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S: Likewise. ++ * sysdeps/unix/sysv/linux/powerpc/powerpc64/vfork.S: Likewise. ++ * sysdeps/unix/sysv/linux/s390/s390-32/vfork.S: Likewise. ++ * sysdeps/unix/sysv/linux/s390/s390-64/vfork.S: Likewise. ++ * sysdeps/unix/sysv/linux/sh/vfork.S: Likewise. ++ * sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S: Likewise. ++ * sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S: Likewise. ++ * sysdeps/unix/sysv/linux/tile/vfork.S: Likewise. ++ * sysdeps/unix/sysv/linux/x86_64/vfork.S: Likewise. ++ * sysdeps/unix/sysv/linux/hppa/pt-vfork.S: Likewise. ++ * sysdeps/unix/sysv/linux/tst-clone2.c (f): Remove direct pthread ++ struct access. ++ (clone_test): Remove function. ++ (do_test): Rewrite to take in consideration pid is not cached anymore. ++ ++2016-09-26 Adhemerval Zanella ++ ++ * sysdeps/unix/sysdep.h (__INTERNAL_SYSCALL0): New macro. ++ (__INTERNAL_SYSCALL1): Likewise. ++ (__INTERNAL_SYSCALL2): Likewise. ++ (__INTERNAL_SYSCALL3): Likewise. ++ (__INTERNAL_SYSCALL4): Likewise. ++ (__INTERNAL_SYSCALL5): Likewise. ++ (__INTERNAL_SYSCALL6): Likewise. ++ (__INTERNAL_SYSCALL7): Likewise. ++ (__INTERNAL_SYSCALL_NARGS_X): Likewise. ++ (__INTERNAL_SYSCALL_NARGS): Likewise. ++ (__INTERNAL_SYSCALL_DISP): Likewise. ++ (INTERNAL_SYSCALL_CALL): Likewise. ++ (__SYSCALL0): Rename to __INLINE_SYSCALL0. ++ (__SYSCALL1): Rename to __INLINE_SYSCALL1. ++ (__SYSCALL2): Rename to __INLINE_SYSCALL2. ++ (__SYSCALL3): Rename to __INLINE_SYSCALL3. ++ (__SYSCALL4): Rename to __INLINE_SYSCALL4. ++ (__SYSCALL5): Rename to __INLINE_SYSCALL5. ++ (__SYSCALL6): Rename to __INLINE_SYSCALL6. ++ (__SYSCALL7): Rename to __INLINE_SYSCALL7. ++ (__SYSCALL_NARGS_X): Rename to __INLINE_SYSCALL_NARGS_X. ++ (__SYSCALL_NARGS): Rename to __INLINE_SYSCALL_NARGS. ++ (__SYSCALL_DISP): Rename to __INLINE_SYSCALL_DISP. ++ (__SYSCALL_CALL): Rename to INLINE_SYSCALL_CALL. ++ (SYSCALL_CANCEL): Replace __SYSCALL_CALL with INLINE_SYSCALL_CALL. ++ ++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-01-05 Joseph Myers ++ ++ [BZ #21026] ++ * sysdeps/unix/sysv/linux/mips/mips64/n64/syscalls.list ++ (readahead): New syscall entry. ++ ++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-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 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-01-30 H.J. Lu ++ ++ [BZ #21081] ++ * sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S ++ (L(stosb)): Add VZEROUPPER before ret. ++ ++2016-11-28 H.J. Lu ++ ++ [BZ #20750] ++ * sysdeps/x86_64/sysdep.h (JUMPTARGET): Check SHARED instead ++ of PIC. ++ ++2016-12-31 Florian Weimer ++ ++ [BZ #18784] ++ CVE-2015-5180 ++ * include/arpa/nameser_compat.h (T_QUERY_A_AND_AAAA): Rename from ++ T_UNSPEC. Adjust value. ++ * resolv/nss_dns/dns-host.c (_nss_dns_gethostbyname4_r): Use it. ++ * resolv/res_query.c (__libc_res_nquery): Likewise. ++ * resolv/res_mkquery.c (res_nmkquery): Check for out-of-range ++ QTYPEs. ++ * resolv/tst-resolv-qtypes.c: New file. ++ * resolv/Makefile (xtests): Add tst-resolv-qtypes. ++ (tst-resolv-qtypes): Link against libresolv and libpthread. ++ ++2017-02-02 Siddhesh Poyarekar ++ ++ * sysdeps/generic/unsecvars.h: Add GLIBC_TUNABLES. ++ ++2017-01-23 Rajalakshmi Srinivasaraghavan ++ Steven Munroe ++ Tulio Magno Quites Machado Filho ++ ++ [BZ #20822] ++ * sysdeps/unix/sysv/linux/powerpc/elision-lock.c ++ (__lll_lock_elision): Access adapt_count via C11 atomics. ++ * sysdeps/unix/sysv/linux/powerpc/elision-trylock.c ++ (__lll_trylock_elision): Likewise. ++ * sysdeps/unix/sysv/linux/powerpc/elision-unlock.c ++ (__lll_unlock_elision): Update adapt_count variable inside the ++ critical section using C11 atomics. ++ ++2016-12-24 Carlos O'Donell ++ ++ [BZ #11941] ++ * elf/dl-close.c (_dl_close): Take dl_load_lock to examine map. ++ Remove assert (map->l_init_called); if DF_1_NODELETE is set. ++ * elf/Makefile [ifeq (yes,$(build-shared))] (tests): Add ++ tst-nodelete-dlclose. ++ (modules-names): Add tst-nodelete-dlclose-dso and ++ tst-nodelete-dlclose-plugin. ++ ($(objpfx)tst-nodelete-dlclose-dso.so): Define. ++ ($(objpfx)tst-nodelete-dlclose-plugin.so): Define. ++ ($(objpfx)tst-nodelete-dlclose): Define. ++ ($(objpfx)tst-nodelete-dlclose.out): Define. ++ ++2016-08-02 Aurelien Jarno ++ ++2016-08-02 Aurelien Jarno ++ ++ * sysdeps/alpha/fpu/s_ceil.c (__ceil): Add argument with itself ++ when it is a NaN. ++ [_IEEE_FP_INEXACT] Remove. ++ * sysdeps/alpha/fpu/s_ceilf.c (__ceilf): Likewise. ++ * sysdeps/alpha/fpu/s_floor.c (__floor): Add argument with itself ++ when it is a NaN. ++ [_IEEE_FP_INEXACT] Remove. ++ * sysdeps/alpha/fpu/s_floorf.c (__floorf): Likewise. ++ * sysdeps/alpha/fpu/s_rint.c (__rint): Add argument with itself ++ when it is a NaN. ++ * sysdeps/alpha/fpu/s_rintf.c (__rintf): Likewise. ++ * sysdeps/alpha/fpu/s_trunc.c (__trunc): Return the input value ++ when its absolute value is greater than 0x1.0p52. ++ [_IEEE_FP_INEXACT] Remove. ++ * sysdeps/alpha/fpu/s_truncf.c (__truncf): Return the input value ++ when its absolute value is greater than 0x1.0p23. ++ [_IEEE_FP_INEXACT] Remove. ++ ++2016-11-30 H.J. Lu ++ ++ [BZ #20495] ++ [BZ #20508] ++ * sysdeps/x86/cpu-features.c (init_cpu_features): For Intel ++ processors, set Use_dl_runtime_resolve_slow and set ++ Use_dl_runtime_resolve_opt if XGETBV suports ECX == 1. ++ * sysdeps/x86/cpu-features.h (bit_arch_Use_dl_runtime_resolve_opt): ++ New. ++ (bit_arch_Use_dl_runtime_resolve_slow): Likewise. ++ (index_arch_Use_dl_runtime_resolve_opt): Likewise. ++ (index_arch_Use_dl_runtime_resolve_slow): Likewise. ++ * sysdeps/x86_64/dl-machine.h (elf_machine_runtime_setup): Use ++ _dl_runtime_resolve_avx512_opt and _dl_runtime_resolve_avx_opt ++ if Use_dl_runtime_resolve_opt is set. Use ++ _dl_runtime_resolve_slow if Use_dl_runtime_resolve_slow is set. ++ * sysdeps/x86_64/dl-trampoline.S: Include . ++ (_dl_runtime_resolve_opt): New. Defined for AVX and AVX512. ++ (_dl_runtime_resolve): Add one for _dl_runtime_resolve_sse_vex. ++ * sysdeps/x86_64/dl-trampoline.h (_dl_runtime_resolve_avx_slow): ++ New. ++ (_dl_runtime_resolve_opt): Likewise. ++ (_dl_runtime_profile): Define only if _dl_runtime_profile is ++ defined. ++ ++2016-11-24 Aurelien Jarno ++ ++ * sysdeps/x86_64/memcpy_chk.S (__memcpy_chk): Check for SHARED ++ instead of PIC. ++ ++2016-11-23 Matthew Fortune ++ Maciej W. Rozycki ++ ++ * sysdeps/mips/mips32/crti.S (_init): Add `.insn' pseudo-op at ++ `.Lno_weak_fn' label. ++ * sysdeps/mips/mips64/n32/crti.S (_init): Likewise. ++ * sysdeps/mips/mips64/n64/crti.S (_init): Likewise. ++ ++2016-11-22 Adhemerval Zanella ++ ++ [BZ #20847] ++ * posix/execvpe.c (maybe_script_execute): Remove write past allocated ++ array bounds. ++ (__execvpe): Likewise. ++ ++2016-11-15 Denis Kaganovich ++ Magnus Granberg ++ Mike Frysinger ++ ++ [BZ #20662] ++ * configure.ac (libc_cv_predef_stack_protector): Also check for ++ __stack_chk_fail_local symbols. ++ * configure: Regenerated. ++ ++2016-11-03 Joseph Myers ++ ++ * conform/Makefile ($(linknamespace-header-tests)): Also depend on ++ $(linknamespace-symlists-tests). ++ ++2016-11-06 Aurelien Jarno ++ ++ * iconv/gconv.h (__gconv_info): Define __data element using a ++ zero-length array. ++ ++2016-10-25 Joseph Myers ++ ++ * sysdeps/powerpc/powerpc32/power6/memset.S (memset): Use cmplwi ++ instead of cmpli. ++ * sysdeps/powerpc/powerpc64/power6/memset.S (memset): Use cmpldi ++ instead of cmpli. ++ ++2016-10-24 Adhemerval Zanella ++ ++ * sysdeps/unix/sysv/linux/pread.c (__libc_pread): Use SYSCALL_LL_PRW. ++ * sysdeps/unix/sysv/linux/pwrite.c (__libc_pwrite): Likewise. ++ * sysdeps/unix/sysv/linux/pread64.c (__libc_pread64): Use ++ SYSCALL_LL64_PRW. ++ * sysdeps/unix/sysv/linux/pwrite64.c (__libc_pwrite64): Likewise. ++ * sysdeps/unix/sysv/linux/sh/kernel-features.h: Define ++ __ASSUME_PRW_DUMMY_ARG. ++ * sysdeps/unix/sysv/linux/sh/pread.c: Remove file. ++ * sysdeps/unix/sysv/linux/sh/pread64.c: Likewise. ++ * sysdeps/unix/sysv/linux/sh/pwrite.c: Likewise. ++ * sysdeps/unix/sysv/linux/sh/pwrite64.c: Likewise. ++ * sysdeps/unix/sysv/linux/sysdep.h: Define SYSCALL_LL_PRW and ++ SYSCALL_LL_PRW64 based on __ASSUME_PRW_DUMMY_ARG. ++ ++2016-10-05 Tulio Magno Quites Machado Filho ++ ++ * sysdeps/powerpc/fpu/libm-test-ulps: Regenerated. ++ ++2016-09-20 Adhemerval Zanella ++ ++ * sysdeps/unix/sysv/linux/spawni.c (__spawnix): Correctly block and unblock ++ all signals when executing the clone vfork child. ++ (SIGALL_SET): Remove macro. ++ ++ * nptl/Makefile (tests): Add tst-exec5. ++ * nptl/tst-exec5.c: New file. ++ * sysdeps/unix/sysv/linux/spawni.c (__spawni): Correctly enable and disable ++ asynchronous cancellation. ++ ++2016-09-19 Tulio Magno Quites Machado Filho ++ ++ [BZ #20615] ++ * sysdeps/powerpc/powerpc32/power9/multiarch/Implies: Replace ++ fpu directory by non-fpu. ++ * sysdeps/powerpc/powerpc64/power9/fpu/Implies: Remove dependency ++ on non-fpu directory from a fpu directory. ++ ++2016-09-02 Roland McGrath ++ ++ * sysdeps/arm/nacl/libc.abilist: Add GLIBC_2.24 A. ++ ++ * sysdeps/nacl/dup.c: Add libc_hidden_def. ++ ++2016-09-02 Roland McGrath ++ ++ * sysdeps/posix/wait3.c: Don't treat STAT_LOC as a union, since it's ++ not any more. ++ ++2016-09-02 Roland McGrath ++ ++ * sysdeps/nacl/clock.c (clock): nacl_abi_clock_t -> nacl_irt_clock_t ++ ++2016-08-17 Florian Weimer ++ ++ Reduce time to expected nptl/tst-once5 failure. ++ * nptl/tst-once5.cc (TIMEOUT): Define. ++ ++2016-08-18 Florian Weimer ++ ++ [BZ #16907] ++ * argp/argp.h: Switch to __BEGIN_DECLS and __END_DECLS. ++ (__THROW, __NTH, __attribute__, __restrict): Remove definitions. ++ * argp/argp-fmtstream.h: Add __BEGIN_DECLS and __END_DECLS. ++ (__attribute__): Remove definition. ++ ++2016-08-15 Andreas Schwab ++ ++ [BZ #20435] ++ * sysdeps/unix/sysv/linux/arm/setcontext.S (__startcontext): Mark ++ as .cantunwind. ++ ++2016-08-17 Florian Weimer ++ ++ [BZ #20452] ++ Avoid additional copies of objects in libc.a in static libraries. ++ * sysdeps/ia64/nptl/Makefile (libpthread-shared-only-routines): ++ Add ptw-sysdep, ptw-sigblock, ptw-sigprocmask. ++ * sysdeps/mips/Makefile (librt-shared-only-routines): Add ++ rt-sysdep. ++ * sysdeps/mips/nptl/Makefile (libpthread-shared-only-routines): ++ Add nptl-sysdep. ++ * sysdeps/s390/nptl/Makefile (libpthread-shared-only-routines): ++ Add ptw-sysdep. ++ * sysdeps/unix/alpha/Makefile (librt-shared-only-routines): Add ++ rt-sysdep. ++ * sysdeps/unix/sysv/linux/alpha/Makefile ++ (libpthread-shared-only-routines): Add ptw-sysdep, ++ ptw-sigprocmask, ptw-rt_sigaction. ++ * sysdeps/unix/sysv/linux/ia64/Makefile ++ (librt-shared-only-routines): Add rt-sysdep. ++ * sysdeps/unix/sysv/linux/i386/Makefile ++ (libpthread-shared-only-routines): Add libc-do-syscall. ++ * sysdeps/unix/sysv/linux/microblaze/Makefile ++ (libpthread-shared-only-routines): Add sysdep. ++ * sysdeps/unix/sysv/linux/powerpc/Makefile ++ (librt-shared-only-routines): Add rt-sysdep. ++ (libpthread-shared-only-routines): Add sysdep. ++ * sysdeps/unix/sysv/linux/s390/Makefile ++ (librt-shared-only-routines): Add rt-sysdep. ++ * sysdeps/unix/sysv/linux/sparc/Makefile ++ (librt-shared-only-routines): Add rt-sysdep. ++ (libpthread-shared-only-routines): Add sysdep. ++ * sysdeps/unix/sysv/linux/tile/Makefile ++ (libpthread-shared-only-routines): Likewise. ++ ++2016-08-05 Aurelien Jarno ++ ++ * sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/Makefile ++ [$(subdir) = math && $(have-as-vis3) = yes] (libm-sysdep_routines): ++ Remove s_fdimf-vis3, s_fdim-vis3. ++ * sysdeps/sparc/sparc32/fpu/s_fdim.S: Delete file. ++ * sysdeps/sparc/sparc32/fpu/s_fdimf.S: Likewise. ++ * sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdim-vis3.S: Likewise. ++ * sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdim.S: Likewise. ++ * sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdimf-vis3.S: Likewise. ++ * sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdimf.S: Likewise. ++ * sysdeps/sparc/sparc32/sparcv9/fpu/s_fdim.S: Likewise. ++ * sysdeps/sparc/sparc32/sparcv9/fpu/s_fdimf.S: Likewise. ++ * sysdeps/sparc/sparc64/fpu/s_fdim.S: Likewise. ++ * sysdeps/sparc/sparc64/fpu/s_fdimf.S: Likewise. ++ ++2016-08-02 David S. Miller ++ ++ * sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_nearbyint-vis3.S ++ (__nearbyint_vis3): Don't check for sNaN before float register is ++ loaded with the incoming argument. ++ * sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_nearbyintf-vis3.S ++ (__nearbyintf_vis3): Likewise. ++ * sysdeps/sparc/sparc32/sparcv9/fpu/s_nearbyint.S (__nearbyint): ++ Likewise. ++ * sysdeps/sparc/sparc32/sparcv9/fpu/s_nearbyintf.S (__nearbyintf): ++ Likewise. ++ ++2016-08-03 Aurelien Jarno ++ ++ * sysdeps/powerpc/ifunc-sel.h (ifunc_sel): Replace beqlr instructions ++ by beq instructions jumping to the end of the function. ++ * sysdeps/powerpc/ifunc-sel.h (ifunc_sel): Add "11", "12", "cr0" to the ++ clobber list. Use "i" constraint instead of "X". ++ (ifunc_one): Add "12" to the clobber list. Use "i" constraint instead ++ of "X". ++ ++2016-08-04 Carlos O'Donell ++ ++ * po/de.po: Update from Translation Project. ++ * po/fi.po: Likewise. ++ * po/sv.po: Likewise. ++ ++2016-08-02 Florian Weimer ++ ++ [BZ #20370] ++ * malloc/arena.c (get_free_list): Update comment. Assert that ++ arenas on the free list have no attached threads. ++ (remove_from_free_list): New function. ++ (reused_arena): Call it. ++ ++2016-08-04 Florian Weimer ++ ++ Use sysdep.o from libc.a in static libraries. ++ * sysdeps/unix/sysv/linux/i386/Makefile ++ (libpthread-shared-only-routines): Add sysdep. ++ (librt-shared-only-routines): Likewise. ++ + 2016-08-01 Carlos O'Donell + + * version.h (RELEASE): Set to "stable" +diff --git a/Makeconfig b/Makeconfig +index 03fd89c13e..ee379f5852 100644 +--- a/Makeconfig ++++ b/Makeconfig +@@ -394,6 +394,9 @@ ifndef after-link + after-link = + endif + ++# Additional libraries to link into every test. ++link-extra-libs-tests = $(libsupport) ++ + # Command for linking PIE programs with the C library. + ifndef +link-pie + +link-pie-before-libc = $(CC) -pie -Wl,-O1 -nostdlib -nostartfiles -o $@ \ +@@ -503,7 +506,7 @@ link-libc = $(link-libc-rpath-link) $(link-libc-before-gnulib) $(gnulib) + link-libc-tests = $(link-libc-tests-rpath-link) \ + $(link-libc-before-gnulib) $(gnulib-tests) + # This is how to find at build-time things that will be installed there. +-rpath-dirs = math elf dlfcn nss nis rt resolv crypt mathvec ++rpath-dirs = math elf dlfcn nss nis rt resolv crypt mathvec support + rpath-link = \ + $(common-objdir):$(subst $(empty) ,:,$(patsubst ../$(subdir),.,$(rpath-dirs:%=$(common-objpfx)%))) + else +@@ -850,7 +853,7 @@ libio-include = -I$(..)libio + # List of non-library modules that we build. + built-modules = iconvprogs iconvdata ldconfig lddlibc4 libmemusage \ + libSegFault libpcprofile librpcsvc locale-programs \ +- memusagestat nonlib nscd extramodules libnldbl ++ memusagestat nonlib nscd extramodules libnldbl libsupport + + in-module = $(subst -,_,$(firstword $(libof-$(basename $(@F))) \ + $(libof-$( + using `glibc' in the "product" field. + ++Version 2.24.1 ++ ++Security related changes: ++ ++* On ARM EABI (32-bit), generating a backtrace for execution contexts which ++ have been created with makecontext could fail to terminate due to a ++ missing .cantunwind annotation. This has been observed to lead to a hang ++ (denial of service) in some Go applications compiled with gccgo. Reported ++ by Andreas Schwab. (CVE-2016-6323) ++ ++* The DNS stub resolver functions would crash due to a NULL pointer ++ dereference when processing a query with a valid DNS question type which ++ was used internally in the implementation. The stub resolver now uses a ++ question type which is outside the range of valid question type values. ++ (CVE-2015-5180) ++ ++* 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. ++ ++ CVE-2018-1000001: Buffer underflow in realpath function when getcwd function ++ succeeds without returning an absolute path due to unexpected behaviour ++ of the Linux kernel getcwd syscall. Reported by halfdog. ++ ++The following bugs are resolved with this release: ++ ++ [20790] Fix rpcgen buffer overrun ++ [20978] Fix strlen on null pointer in nss_nisplus ++ [21209] Ignore and remove LD_HWCAP_MASK for AT_SECURE programs ++ [21265] x86-64: Use fxsave/xsave/xsavec in _dl_runtime_resolve ++ [21289] Fix symbol redirect for fts_set ++ [21386] Assertion in fork for distinct parent PID is incorrect ++ [21609] x86-64: Align the stack in __tls_get_addr ++ [21624] Unsafe alloca allows local attackers to alias stack and heap (CVE-2017-1000366) ++ [21654] nss: Fix invalid cast in group merging ++ [22679] getcwd(3) can succeed without returning an absolute path ++ (CVE-2018-1000001) ++ + Version 2.24 + + * The minimum Linux kernel version that this version of the GNU C Library +diff --git a/Rules b/Rules +index 8306d36a07..a981965d2b 100644 +--- a/Rules ++++ b/Rules +@@ -149,6 +149,7 @@ endif + + ifneq "$(strip $(binaries-shared-tests))" "" + $(addprefix $(objpfx),$(binaries-shared-tests)): %: %.o \ ++ $(link-extra-libs-tests) \ + $(sort $(filter $(common-objpfx)lib%,$(link-libc))) \ + $(addprefix $(csu-objpfx),start.o) $(+preinit) $(+postinit) + $(+link-tests) +@@ -156,6 +157,7 @@ endif + + ifneq "$(strip $(binaries-pie-tests))" "" + $(addprefix $(objpfx),$(binaries-pie-tests)): %: %.o \ ++ $(link-extra-libs-tests) \ + $(sort $(filter $(common-objpfx)lib%,$(link-libc))) \ + $(addprefix $(csu-objpfx),start.o) $(+preinit) $(+postinit) + $(+link-pie-tests) +@@ -177,6 +179,7 @@ endif + + ifneq "$(strip $(binaries-static-tests))" "" + $(addprefix $(objpfx),$(binaries-static-tests)): %: %.o \ ++ $(link-extra-libs-tests) \ + $(sort $(filter $(common-objpfx)lib%,$(link-libc-static-tests))) \ + $(addprefix $(csu-objpfx),start.o) $(+preinit) $(+postinit) + $(+link-static-tests) +diff --git a/argp/argp-fmtstream.h b/argp/argp-fmtstream.h +index bdeaa54dc2..e8c5797f38 100644 +--- a/argp/argp-fmtstream.h ++++ b/argp/argp-fmtstream.h +@@ -29,21 +29,6 @@ + #include + #include + +-#ifndef __attribute__ +-/* This feature is available in gcc versions 2.5 and later. */ +-# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || \ +- defined __STRICT_ANSI__ +-# define __attribute__(Spec) /* empty */ +-# endif +-/* The __-protected variants of `format' and `printf' attributes +- are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */ +-# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) || \ +- defined __STRICT_ANSI__ +-# define __format__ format +-# define __printf__ printf +-# endif +-#endif +- + #if defined (__GNU_LIBRARY__) && defined (HAVE_LINEWRAP_H) + /* line_wrap_stream is available, so use that. */ + #define ARGP_FMTSTREAM_USE_LINEWRAP +@@ -111,6 +96,8 @@ struct argp_fmtstream + + typedef struct argp_fmtstream *argp_fmtstream_t; + ++__BEGIN_DECLS ++ + /* Return an argp_fmtstream that outputs to STREAM, and which prefixes lines + written on it with LMARGIN spaces and limits them to RMARGIN columns + total. If WMARGIN >= 0, words that extend past RMARGIN are wrapped by +@@ -297,6 +284,8 @@ __argp_fmtstream_point (argp_fmtstream_t __fs) + + #endif /* __OPTIMIZE__ */ + ++__END_DECLS ++ + #endif /* ARGP_FMTSTREAM_USE_LINEWRAP */ + + #endif /* argp-fmtstream.h */ +diff --git a/argp/argp.h b/argp/argp.h +index e67bbef739..7cb5a69f08 100644 +--- a/argp/argp.h ++++ b/argp/argp.h +@@ -28,48 +28,12 @@ + #define __need_error_t + #include + +-#ifndef __THROW +-# define __THROW +-#endif +-#ifndef __NTH +-# define __NTH(fct) fct __THROW +-#endif +- +-#ifndef __attribute__ +-/* This feature is available in gcc versions 2.5 and later. */ +-# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || \ +- defined __STRICT_ANSI__ +-# define __attribute__(Spec) /* empty */ +-# endif +-/* The __-protected variants of `format' and `printf' attributes +- are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */ +-# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) || \ +- defined __STRICT_ANSI__ +-# define __format__ format +-# define __printf__ printf +-# endif +-#endif +- +-/* GCC 2.95 and later have "__restrict"; C99 compilers have +- "restrict", and "configure" may have defined "restrict". */ +-#ifndef __restrict +-# if ! (2 < __GNUC__ || (2 == __GNUC__ && 95 <= __GNUC_MINOR__)) +-# if defined restrict || 199901L <= __STDC_VERSION__ +-# define __restrict restrict +-# else +-# define __restrict +-# endif +-# endif +-#endif +- + #ifndef __error_t_defined + typedef int error_t; + # define __error_t_defined + #endif + +-#ifdef __cplusplus +-extern "C" { +-#endif ++__BEGIN_DECLS + + /* A description of a particular option. A pointer to an array of + these is passed in the OPTIONS field of an argp structure. Each option +@@ -590,8 +554,6 @@ __NTH (__option_is_end (const struct argp_option *__opt)) + # endif + #endif /* Use extern inlines. */ + +-#ifdef __cplusplus +-} +-#endif ++__END_DECLS + + #endif /* argp.h */ +diff --git a/configure b/configure +index 17625e1041..9b5a486048 100755 +--- a/configure ++++ b/configure +@@ -6289,12 +6289,14 @@ echo >&5 "libc_undefs='$libc_undefs'" + # symbols (resolved by the linker), so filter out unknown symbols. + # This will fail to produce the correct result if the compiler + # defaults to -fstack-protector but this produces an undefined symbol +-# other than __stack_chk_fail. However, compilers like that have not +-# been encountered in practice. +-libc_undefs=`echo "$libc_undefs" | egrep '^(foobar|__stack_chk_fail)$'` ++# other than __stack_chk_fail or __stack_chk_fail_local. However, ++# compilers like that have not been encountered in practice. ++libc_undefs=`echo "$libc_undefs" | \ ++ egrep '^(foobar|__stack_chk_fail|__stack_chk_fail_local)$'` + case "$libc_undefs" in + foobar) libc_cv_predef_stack_protector=no ;; + '__stack_chk_fail ++foobar'|'__stack_chk_fail_local + foobar') libc_cv_predef_stack_protector=yes ;; + *) as_fn_error $? "unexpected symbols in test: $libc_undefs" "$LINENO" 5 ;; + esac +diff --git a/configure.ac b/configure.ac +index 33bcd62180..8277d9f727 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1626,12 +1626,14 @@ echo >&AS_MESSAGE_LOG_FD "libc_undefs='$libc_undefs'" + # symbols (resolved by the linker), so filter out unknown symbols. + # This will fail to produce the correct result if the compiler + # defaults to -fstack-protector but this produces an undefined symbol +-# other than __stack_chk_fail. However, compilers like that have not +-# been encountered in practice. +-libc_undefs=`echo "$libc_undefs" | egrep '^(foobar|__stack_chk_fail)$'` ++# other than __stack_chk_fail or __stack_chk_fail_local. However, ++# compilers like that have not been encountered in practice. ++libc_undefs=`echo "$libc_undefs" | \ ++ egrep '^(foobar|__stack_chk_fail|__stack_chk_fail_local)$'` + case "$libc_undefs" in + foobar) libc_cv_predef_stack_protector=no ;; + '__stack_chk_fail ++foobar'|'__stack_chk_fail_local + foobar') libc_cv_predef_stack_protector=yes ;; + *) AC_MSG_ERROR([unexpected symbols in test: $libc_undefs]) ;; + esac], +diff --git a/conform/Makefile b/conform/Makefile +index 32a0937b06..7883624c81 100644 +--- a/conform/Makefile ++++ b/conform/Makefile +@@ -196,13 +196,13 @@ $(conformtest-header-tests): $(objpfx)%/conform.out: \ + conformtest.pl $(conformtest-headers-data) + (set -e; std_hdr=$*; std=$${std_hdr%%/*}; hdr=$${std_hdr#*/}; \ + mkdir -p $(@D)/scratch; \ +- $(PERL) conformtest.pl --tmpdir=$(@D)/scratch --cc='$(CC)' \ ++ $(PERL) -I. conformtest.pl --tmpdir=$(@D)/scratch --cc='$(CC)' \ + --flags='$(conformtest-cc-flags)' --standard=$$std \ + --headers=$$hdr > $@); \ + $(evaluate-test) + + $(linknamespace-symlists-tests): $(objpfx)symlist-%: list-header-symbols.pl +- $(PERL) -w $< --tmpdir=$(objpfx) --cc='$(CC)' \ ++ $(PERL) -I. -w $< --tmpdir=$(objpfx) --cc='$(CC)' \ + --flags='$(conformtest-cc-flags)' --standard=$* \ + --headers="$(strip $(conformtest-headers-$*))" \ + > $@ 2> $@.err; \ +@@ -229,10 +229,11 @@ $(linknamespace-symlist-stdlibs-tests): $(objpfx)symlist-stdlibs-%: \ + + $(linknamespace-header-tests): $(objpfx)%/linknamespace.out: \ + linknamespace.pl \ ++ $(linknamespace-symlists-tests) \ + $(linknamespace-symlist-stdlibs-tests) + (set -e; std_hdr=$*; std=$${std_hdr%%/*}; hdr=$${std_hdr#*/}; \ + mkdir -p $(@D)/scratch; \ +- $(PERL) -w $< --tmpdir=$(@D)/scratch --cc='$(CC)' \ ++ $(PERL) -I. -w $< --tmpdir=$(@D)/scratch --cc='$(CC)' \ + --flags='$(conformtest-cc-flags)' --standard=$$std \ + --stdsyms=$(objpfx)symlist-$$std --header=$$hdr \ + --libsyms=$(objpfx)symlist-stdlibs-$$std \ +diff --git a/elf/Makefile b/elf/Makefile +index 593403c640..847a012f84 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -149,7 +149,8 @@ tests += loadtest restest1 preloadtest loadfail multiload origtest resolvfail \ + tst-nodelete) \ + tst-initorder tst-initorder2 tst-relsort1 tst-null-argv \ + tst-ptrguard1 tst-tlsalign tst-tlsalign-extern tst-nodelete-opened \ +- tst-nodelete2 tst-audit11 tst-audit12 tst-dlsym-error ++ tst-nodelete2 tst-audit11 tst-audit12 tst-dlsym-error \ ++ tst-nodelete-dlclose + # reldep9 + ifeq ($(build-hardcoded-path-in-tests),yes) + tests += tst-dlopen-aout +@@ -223,7 +224,8 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ + tst-array5dep tst-null-argv-lib \ + tst-tlsalign-lib tst-nodelete-opened-lib tst-nodelete2mod \ + tst-audit11mod1 tst-audit11mod2 tst-auditmod11 \ +- tst-audit12mod1 tst-audit12mod2 tst-audit12mod3 tst-auditmod12 ++ tst-audit12mod1 tst-audit12mod2 tst-audit12mod3 tst-auditmod12 \ ++ tst-nodelete-dlclose-dso tst-nodelete-dlclose-plugin + ifeq (yes,$(have-mtls-dialect-gnu2)) + tests += tst-gnu2-tls1 + modules-names += tst-gnu2-tls1mod +@@ -1267,3 +1269,12 @@ $(objpfx)tst-ldconfig-X.out : tst-ldconfig-X.sh $(objpfx)ldconfig + $(evaluate-test) + + $(objpfx)tst-dlsym-error: $(libdl) ++ ++# The application depends on the DSO, and the DSO loads the plugin. ++# The plugin also depends on the DSO. This creates the circular ++# dependency via dlopen that we're testing to make sure works. ++$(objpfx)tst-nodelete-dlclose-dso.so: $(libdl) ++$(objpfx)tst-nodelete-dlclose-plugin.so: $(objpfx)tst-nodelete-dlclose-dso.so ++$(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 +diff --git a/elf/dl-close.c b/elf/dl-close.c +index 687d7de874..9f93ab7628 100644 +--- a/elf/dl-close.c ++++ b/elf/dl-close.c +@@ -805,19 +805,37 @@ _dl_close (void *_map) + { + struct link_map *map = _map; + +- /* First see whether we can remove the object at all. */ ++ /* We must take the lock to examine the contents of map and avoid ++ concurrent dlopens. */ ++ __rtld_lock_lock_recursive (GL(dl_load_lock)); ++ ++ /* At this point we are guaranteed nobody else is touching the list of ++ loaded maps, but a concurrent dlclose might have freed our map ++ before we took the lock. There is no way to detect this (see below) ++ so we proceed assuming this isn't the case. First see whether we ++ can remove the object at all. */ + if (__glibc_unlikely (map->l_flags_1 & DF_1_NODELETE)) + { +- assert (map->l_init_called); + /* Nope. Do nothing. */ ++ __rtld_lock_unlock_recursive (GL(dl_load_lock)); + return; + } + ++ /* At present this is an unreliable check except in the case where the ++ caller has recursively called dlclose and we are sure the link map ++ has not been freed. In a non-recursive dlclose the map itself ++ might have been freed and this access is potentially a data race ++ with whatever other use this memory might have now, or worse we ++ might silently corrupt memory if it looks enough like a link map. ++ POSIX has language in dlclose that appears to guarantee that this ++ should be a detectable case and given that dlclose should be threadsafe ++ we need this to be a reliable detection. ++ This is bug 20990. */ + if (__builtin_expect (map->l_direct_opencount, 1) == 0) +- GLRO(dl_signal_error) (0, map->l_name, NULL, N_("shared object not open")); +- +- /* Acquire the lock. */ +- __rtld_lock_lock_recursive (GL(dl_load_lock)); ++ { ++ __rtld_lock_unlock_recursive (GL(dl_load_lock)); ++ _dl_signal_error (0, map->l_name, NULL, N_("shared object not open")); ++ } + + _dl_close_worker (map, false); + +diff --git a/elf/dl-load.c b/elf/dl-load.c +index c0d6249373..1f774e139f 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/rtld.c b/elf/rtld.c +index 647661ca45..8f56d6edd3 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 +@@ -730,6 +837,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, +@@ -1257,11 +1400,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. */ +@@ -1272,9 +1417,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 +@@ -1283,7 +1433,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; +@@ -1296,7 +1446,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); + } +@@ -1400,10 +1550,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. */ +@@ -1481,23 +1628,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); +@@ -1682,7 +1814,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 (); +@@ -2313,9 +2445,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. */ +@@ -2379,7 +2509,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: +@@ -2423,7 +2553,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; +@@ -2437,7 +2568,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-nodelete-dlclose-dso.c b/elf/tst-nodelete-dlclose-dso.c +new file mode 100644 +index 0000000000..dd930f99cc +--- /dev/null ++++ b/elf/tst-nodelete-dlclose-dso.c +@@ -0,0 +1,90 @@ ++/* Bug 11941: Improper assert map->l_init_called in dlclose. ++ Copyright (C) 2016 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 is the primary DSO that is loaded by the appliation. This DSO ++ then loads a plugin with RTLD_NODELETE. This plugin depends on this ++ DSO. This dependency chain means that at application shutdown the ++ plugin will be destructed first. Thus by the time this DSO is ++ destructed we will be calling dlclose on an object that has already ++ been destructed. It is allowed to call dlclose in this way and ++ should not assert. */ ++#include ++#include ++#include ++ ++/* Plugin to load. */ ++static void *plugin_lib = NULL; ++/* Plugin function. */ ++static void (*plugin_func) (void); ++#define LIB_PLUGIN "tst-nodelete-dlclose-plugin.so" ++ ++/* This function is never called but the plugin references it. ++ We do this to avoid any future --as-needed from removing the ++ plugin's DT_NEEDED on this DSO (required for the test). */ ++void ++primary_reference (void) ++{ ++ printf ("INFO: Called primary_reference function.\n"); ++} ++ ++void ++primary (void) ++{ ++ char *error; ++ ++ plugin_lib = dlopen (LIB_PLUGIN, RTLD_NOW | RTLD_LOCAL | RTLD_NODELETE); ++ if (plugin_lib == NULL) ++ { ++ printf ("ERROR: Unable to load plugin library.\n"); ++ exit (EXIT_FAILURE); ++ } ++ dlerror (); ++ ++ plugin_func = (void (*) (void)) dlsym (plugin_lib, "plugin_func"); ++ error = dlerror (); ++ if (error != NULL) ++ { ++ printf ("ERROR: Unable to find symbol with error \"%s\".", ++ error); ++ exit (EXIT_FAILURE); ++ } ++ ++ return; ++} ++ ++__attribute__ ((destructor)) ++static void ++primary_dtor (void) ++{ ++ int ret; ++ ++ printf ("INFO: Calling primary destructor.\n"); ++ ++ /* The destructor runs in the test driver also, which ++ hasn't called primary, in that case do nothing. */ ++ if (plugin_lib == NULL) ++ return; ++ ++ ret = dlclose (plugin_lib); ++ if (ret != 0) ++ { ++ printf ("ERROR: Calling dlclose failed with \"%s\"\n", ++ dlerror ()); ++ exit (EXIT_FAILURE); ++ } ++} +diff --git a/elf/tst-nodelete-dlclose-plugin.c b/elf/tst-nodelete-dlclose-plugin.c +new file mode 100644 +index 0000000000..8b295c1718 +--- /dev/null ++++ b/elf/tst-nodelete-dlclose-plugin.c +@@ -0,0 +1,40 @@ ++/* Bug 11941: Improper assert map->l_init_called in dlclose. ++ Copyright (C) 2016 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 DSO simulates a plugin with a dependency on the ++ primary DSO loaded by the appliation. */ ++#include ++ ++extern void primary_reference (void); ++ ++void ++plugin_func (void) ++{ ++ printf ("INFO: Calling plugin function.\n"); ++ /* Need a reference to the DSO to ensure that a potential --as-needed ++ doesn't remove the DT_NEEDED entry which we rely upon to ensure ++ destruction ordering. */ ++ primary_reference (); ++} ++ ++__attribute__ ((destructor)) ++static void ++plugin_dtor (void) ++{ ++ printf ("INFO: Calling plugin destructor.\n"); ++} +diff --git a/elf/tst-nodelete-dlclose.c b/elf/tst-nodelete-dlclose.c +new file mode 100644 +index 0000000000..b3d07e1849 +--- /dev/null ++++ b/elf/tst-nodelete-dlclose.c +@@ -0,0 +1,36 @@ ++/* Bug 11941: Improper assert map->l_init_called in dlclose. ++ Copyright (C) 2016 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 simulates an application using the primary DSO which loads the ++ plugin DSO. */ ++#include ++#include ++ ++extern void primary (void); ++ ++static int ++do_test (void) ++{ ++ printf ("INFO: Starting application.\n"); ++ primary (); ++ printf ("INFO: Exiting application.\n"); ++ return 0; ++} ++ ++#define TEST_FUNCTION do_test () ++#include "../test-skeleton.c" +diff --git a/extra-lib.mk b/extra-lib.mk +index b10748d185..2552049135 100644 +--- a/extra-lib.mk ++++ b/extra-lib.mk +@@ -5,6 +5,9 @@ + # The variable $($(lib)-routines) defines the list of modules + # to be included in that library. A sysdep Makefile can add to + # $(lib)-sysdep_routines to include additional modules. ++# ++# Libraries listed in $(extra-libs-noinstall) are built, but not ++# installed. + + lib := $(firstword $(extra-libs-left)) + extra-libs-left := $(filter-out $(lib),$(extra-libs-left)) +@@ -28,7 +31,9 @@ extra-objs := $(extra-objs) + all-$(lib)-routines := $($(lib)-routines) $($(lib)-sysdep_routines) + + # Add each flavor of library to the lists of things to build and install. ++ifeq (,$(filter $(lib), $(extra-libs-noinstall))) + install-lib += $(foreach o,$(object-suffixes-$(lib)),$(lib:lib%=$(libtype$o))) ++endif + extra-objs += $(foreach o,$(filter-out .os .oS,$(object-suffixes-$(lib))),\ + $(patsubst %,%$o,$(filter-out \ + $($(lib)-shared-only-routines),\ +diff --git a/grp/grp-merge.c b/grp/grp-merge.c +index 0a1eb38d2c..5f79755798 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/iconv/gconv.h b/iconv/gconv.h +index 8d8ce5813b..a87028047b 100644 +--- a/iconv/gconv.h ++++ b/iconv/gconv.h +@@ -139,7 +139,7 @@ typedef struct __gconv_info + { + size_t __nsteps; + struct __gconv_step *__steps; +- __extension__ struct __gconv_step_data __data __flexarr; ++ __extension__ struct __gconv_step_data __data[0]; + } *__gconv_t; + + /* Transliteration using the locale's data. */ +diff --git a/include/arpa/nameser_compat.h b/include/arpa/nameser_compat.h +index 2e735ede4c..7c0deed9ae 100644 +--- a/include/arpa/nameser_compat.h ++++ b/include/arpa/nameser_compat.h +@@ -1,8 +1,8 @@ + #ifndef _ARPA_NAMESER_COMPAT_ + #include + +-/* Picksome unused number to represent lookups of IPv4 and IPv6 (i.e., +- T_A and T_AAAA). */ +-#define T_UNSPEC 62321 ++/* The number is outside the 16-bit RR type range and is used ++ internally by the implementation. */ ++#define T_QUERY_A_AND_AAAA 439963904 + + #endif +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/io/Makefile b/io/Makefile +index deb6100156..1128f4881f 100644 +--- a/io/Makefile ++++ b/io/Makefile +@@ -71,7 +71,8 @@ tests := test-utime test-stat test-stat2 test-lfs tst-getcwd \ + tst-renameat tst-fchownat tst-fchmodat tst-faccessat \ + tst-symlinkat tst-linkat tst-readlinkat tst-mkdirat \ + tst-mknodat tst-mkfifoat tst-ttyname_r bug-ftw5 \ +- tst-posix_fallocate tst-fts tst-fts-lfs ++ tst-posix_fallocate tst-posix_fallocate64 \ ++ tst-fts tst-fts-lfs tst-open-tmpfile tst-getcwd-abspath + + ifeq ($(run-built-tests),yes) + tests-special += $(objpfx)ftwtest.out +diff --git a/io/fts.h b/io/fts.h +index 127a0d2721..b6b45206c8 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/io/tst-getcwd-abspath.c b/io/tst-getcwd-abspath.c +new file mode 100644 +index 0000000000..3a3636f2ed +--- /dev/null ++++ b/io/tst-getcwd-abspath.c +@@ -0,0 +1,66 @@ ++/* BZ #22679 getcwd(3) should not succeed without returning an absolute path. ++ ++ Copyright (C) 2018 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 ++ ++static char *chroot_dir; ++ ++/* The actual test. Run it in a subprocess, so that the test harness ++ can remove the temporary directory in --direct mode. */ ++static void ++getcwd_callback (void *closure) ++{ ++ xchroot (chroot_dir); ++ ++ errno = 0; ++ char *cwd = getcwd (NULL, 0); ++ TEST_COMPARE (errno, ENOENT); ++ TEST_VERIFY (cwd == NULL); ++ ++ errno = 0; ++ cwd = realpath (".", NULL); ++ TEST_COMPARE (errno, ENOENT); ++ TEST_VERIFY (cwd == NULL); ++ ++ _exit (0); ++} ++ ++static int ++do_test (void) ++{ ++ support_become_root (); ++ if (!support_can_chroot ()) ++ return EXIT_UNSUPPORTED; ++ ++ chroot_dir = support_create_temp_directory ("tst-getcwd-abspath-"); ++ support_isolate_in_subprocess (getcwd_callback, NULL); ++ ++ return 0; ++} ++ ++#include +diff --git a/localedata/ChangeLog b/localedata/ChangeLog +index 4be8afc110..a7688e3df6 100644 +--- a/localedata/ChangeLog ++++ b/localedata/ChangeLog +@@ -1,3 +1,17 @@ ++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. ++ ++2016-12-30 Mike Frysinger ++ ++ [BZ #20974] ++ * localedata/bs_BA (LC_MESSAGES): Delete "*." from the end of ++ yesexpr and noexpr. ++ + 2016-07-07 Aurelien Jarno + + * locales/de_LI (postal_fmt): Fix indentation. +diff --git a/localedata/locales/bs_BA b/localedata/locales/bs_BA +index a47f87eb37..68c2f9471a 100644 +--- a/localedata/locales/bs_BA ++++ b/localedata/locales/bs_BA +@@ -148,8 +148,8 @@ copy "en_DK" + END LC_CTYPE + + LC_MESSAGES +-yesexpr "" +-noexpr "" ++yesexpr "" ++noexpr "" + yesstr "" + nostr "" + END LC_MESSAGES +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 229783f3b7..4e16593d8b 100644 +--- a/malloc/arena.c ++++ b/malloc/arena.c +@@ -702,8 +702,7 @@ _int_new_arena (size_t size) + } + + +-/* Remove an arena from free_list. The arena may be in use because it +- was attached concurrently to a thread by reused_arena below. */ ++/* Remove an arena from free_list. */ + static mstate + get_free_list (void) + { +@@ -718,7 +717,8 @@ get_free_list (void) + free_list = result->next_free; + + /* The arena will be attached to this thread. */ +- ++result->attached_threads; ++ assert (result->attached_threads == 0); ++ result->attached_threads = 1; + + detach_arena (replaced_arena); + } +@@ -735,6 +735,26 @@ get_free_list (void) + return result; + } + ++/* Remove the arena from the free list (if it is present). ++ free_list_lock must have been acquired by the caller. */ ++static void ++remove_from_free_list (mstate arena) ++{ ++ mstate *previous = &free_list; ++ for (mstate p = free_list; p != NULL; p = p->next_free) ++ { ++ assert (p->attached_threads == 0); ++ if (p == arena) ++ { ++ /* Remove the requested arena from the list. */ ++ *previous = p->next_free; ++ break; ++ } ++ else ++ previous = &p->next_free; ++ } ++} ++ + /* Lock and return an arena that can be reused for memory allocation. + Avoid AVOID_ARENA as we have already failed to allocate memory in + it and it is currently locked. */ +@@ -782,14 +802,25 @@ reused_arena (mstate avoid_arena) + (void) mutex_lock (&result->mutex); + + out: +- /* Attach the arena to the current thread. Note that we may have +- selected an arena which was on free_list. */ ++ /* Attach the arena to the current thread. */ + { + /* Update the arena thread attachment counters. */ + mstate replaced_arena = thread_arena; + (void) mutex_lock (&free_list_lock); + detach_arena (replaced_arena); ++ ++ /* We may have picked up an arena on the free list. We need to ++ preserve the invariant that no arena on the free list has a ++ positive attached_threads counter (otherwise, ++ arena_thread_freeres cannot use the counter to determine if the ++ arena needs to be put on the free list). We unconditionally ++ remove the selected arena from the free list. The caller of ++ reused_arena checked the free list and observed it to be empty, ++ so the list is very short. */ ++ remove_from_free_list (result); ++ + ++result->attached_threads; ++ + (void) mutex_unlock (&free_list_lock); + } + +diff --git a/misc/regexp.c b/misc/regexp.c +index 3b3668272f..b2a2c6e636 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/nis/nss_nisplus/nisplus-alias.c b/nis/nss_nisplus/nisplus-alias.c +index 7f698b4e6d..cb5acce01d 100644 +--- a/nis/nss_nisplus/nisplus-alias.c ++++ b/nis/nss_nisplus/nisplus-alias.c +@@ -291,7 +291,7 @@ _nss_nisplus_getaliasbyname_r (const char *name, struct aliasent *alias, + return status; + } + +- if (name != NULL) ++ if (name == NULL) + { + *errnop = EINVAL; + return NSS_STATUS_UNAVAIL; +diff --git a/nptl/Makefile b/nptl/Makefile +index 0d8aadebed..fa925819ca 100644 +--- a/nptl/Makefile ++++ b/nptl/Makefile +@@ -268,7 +268,7 @@ tests = tst-typesizes \ + tst-flock1 tst-flock2 \ + tst-signal1 tst-signal2 tst-signal3 tst-signal4 tst-signal5 \ + tst-signal6 tst-signal7 \ +- tst-exec1 tst-exec2 tst-exec3 tst-exec4 \ ++ tst-exec1 tst-exec2 tst-exec3 tst-exec4 tst-exec5 \ + tst-exit1 tst-exit2 tst-exit3 \ + tst-stdio1 tst-stdio2 \ + tst-stack1 tst-stack2 tst-stack3 tst-stack4 tst-pthread-getattr \ +diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c +index 6b42b11d5a..7365ca606b 100644 +--- a/nptl/allocatestack.c ++++ b/nptl/allocatestack.c +@@ -440,9 +440,6 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp, + SETUP_THREAD_SYSINFO (pd); + #endif + +- /* The process ID is also the same as that of the caller. */ +- pd->pid = THREAD_GETMEM (THREAD_SELF, pid); +- + /* Don't allow setxid until cloned. */ + pd->setxid_futex = -1; + +@@ -579,9 +576,6 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp, + /* Don't allow setxid until cloned. */ + pd->setxid_futex = -1; + +- /* The process ID is also the same as that of the caller. */ +- pd->pid = THREAD_GETMEM (THREAD_SELF, pid); +- + /* Allocate the DTV for this thread. */ + if (_dl_allocate_tls (TLS_TPADJ (pd)) == NULL) + { +@@ -875,9 +869,6 @@ __reclaim_stacks (void) + /* This marks the stack as free. */ + curp->tid = 0; + +- /* The PID field must be initialized for the new process. */ +- curp->pid = self->pid; +- + /* Account for the size of the stack. */ + stack_cache_actsize += curp->stackblock_size; + +@@ -903,13 +894,6 @@ __reclaim_stacks (void) + } + } + +- /* Reset the PIDs in any cached stacks. */ +- list_for_each (runp, &stack_cache) +- { +- struct pthread *curp = list_entry (runp, struct pthread, list); +- curp->pid = self->pid; +- } +- + /* Add the stack of all running threads to the cache. */ + list_splice (&stack_used, &stack_cache); + +@@ -1054,9 +1038,9 @@ setxid_signal_thread (struct xid_command *cmdp, struct pthread *t) + return 0; + + int val; ++ pid_t pid = __getpid (); + INTERNAL_SYSCALL_DECL (err); +- val = INTERNAL_SYSCALL (tgkill, err, 3, THREAD_GETMEM (THREAD_SELF, pid), +- t->tid, SIGSETXID); ++ val = INTERNAL_SYSCALL_CALL (tgkill, err, pid, t->tid, SIGSETXID); + + /* If this failed, it must have had not started yet or else exited. */ + if (!INTERNAL_SYSCALL_ERROR_P (val, err)) +diff --git a/nptl/descr.h b/nptl/descr.h +index 8e4938deb5..bc92abf010 100644 +--- a/nptl/descr.h ++++ b/nptl/descr.h +@@ -167,8 +167,8 @@ struct pthread + therefore stack) used' flag. */ + pid_t tid; + +- /* Process ID - thread group ID in kernel speak. */ +- pid_t pid; ++ /* Ununsed. */ ++ pid_t pid_ununsed; + + /* List of robust mutexes the thread is holding. */ + #ifdef __PTHREAD_MUTEX_HAVE_PREV +diff --git a/nptl/nptl-init.c b/nptl/nptl-init.c +index bdbdfedcef..48fab50c4e 100644 +--- a/nptl/nptl-init.c ++++ b/nptl/nptl-init.c +@@ -184,18 +184,12 @@ __nptl_set_robust (struct pthread *self) + static void + sigcancel_handler (int sig, siginfo_t *si, void *ctx) + { +- /* Determine the process ID. It might be negative if the thread is +- in the middle of a fork() call. */ +- pid_t pid = THREAD_GETMEM (THREAD_SELF, pid); +- if (__glibc_unlikely (pid < 0)) +- pid = -pid; +- + /* Safety check. It would be possible to call this function for + other signals and send a signal from another process. This is not + correct and might even be a security problem. Try to catch as + many incorrect invocations as possible. */ + if (sig != SIGCANCEL +- || si->si_pid != pid ++ || si->si_pid != __getpid() + || si->si_code != SI_TKILL) + return; + +@@ -243,19 +237,14 @@ struct xid_command *__xidcmd attribute_hidden; + static void + sighandler_setxid (int sig, siginfo_t *si, void *ctx) + { +- /* Determine the process ID. It might be negative if the thread is +- in the middle of a fork() call. */ +- pid_t pid = THREAD_GETMEM (THREAD_SELF, pid); + int result; +- if (__glibc_unlikely (pid < 0)) +- pid = -pid; + + /* Safety check. It would be possible to call this function for + other signals and send a signal from another process. This is not + correct and might even be a security problem. Try to catch as + many incorrect invocations as possible. */ + if (sig != SIGSETXID +- || si->si_pid != pid ++ || si->si_pid != __getpid () + || si->si_code != SI_TKILL) + return; + +diff --git a/nptl/pthread_cancel.c b/nptl/pthread_cancel.c +index 1419baf988..89d02e1741 100644 +--- a/nptl/pthread_cancel.c ++++ b/nptl/pthread_cancel.c +@@ -22,7 +22,7 @@ + #include "pthreadP.h" + #include + #include +- ++#include + + int + pthread_cancel (pthread_t th) +@@ -66,19 +66,11 @@ pthread_cancel (pthread_t th) + #ifdef SIGCANCEL + /* The cancellation handler will take care of marking the + thread as canceled. */ +- INTERNAL_SYSCALL_DECL (err); +- +- /* One comment: The PID field in the TCB can temporarily be +- changed (in fork). But this must not affect this code +- here. Since this function would have to be called while +- the thread is executing fork, it would have to happen in +- a signal handler. But this is no allowed, pthread_cancel +- is not guaranteed to be async-safe. */ +- int val; +- val = INTERNAL_SYSCALL (tgkill, err, 3, +- THREAD_GETMEM (THREAD_SELF, pid), pd->tid, +- SIGCANCEL); ++ pid_t pid = getpid (); + ++ INTERNAL_SYSCALL_DECL (err); ++ int val = INTERNAL_SYSCALL_CALL (tgkill, err, pid, pd->tid, ++ SIGCANCEL); + if (INTERNAL_SYSCALL_ERROR_P (val, err)) + result = INTERNAL_SYSCALL_ERRNO (val, err); + #else +diff --git a/nptl/pthread_getattr_np.c b/nptl/pthread_getattr_np.c +index fb906f0484..32d7484bf8 100644 +--- a/nptl/pthread_getattr_np.c ++++ b/nptl/pthread_getattr_np.c +@@ -68,7 +68,6 @@ pthread_getattr_np (pthread_t thread_id, pthread_attr_t *attr) + { + /* No stack information available. This must be for the initial + thread. Get the info in some magical way. */ +- assert (abs (thread->pid) == thread->tid); + + /* Stack size limit. */ + struct rlimit rl; +diff --git a/nptl/tst-exec5.c b/nptl/tst-exec5.c +new file mode 100644 +index 0000000000..4327d8d41c +--- /dev/null ++++ b/nptl/tst-exec5.c +@@ -0,0 +1,196 @@ ++/* Check if posix_spawn does not act as a cancellation entrypoint. ++ Copyright (C) 2016 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 ++ ++static int do_test (void); ++#define TEST_FUNCTION do_test () ++#include ++ ++static pthread_barrier_t b; ++ ++static pid_t pid; ++static int pipefd[2]; ++ ++static void * ++tf (void *arg) ++{ ++ int r = pthread_barrier_wait (&b); ++ if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) ++ { ++ puts ("error: pthread_barrier_wait failed"); ++ exit (1); ++ } ++ ++ posix_spawn_file_actions_t a; ++ if (posix_spawn_file_actions_init (&a) != 0) ++ { ++ puts ("error: spawn_file_actions_init failed"); ++ exit (1); ++ } ++ ++ if (posix_spawn_file_actions_adddup2 (&a, pipefd[1], STDOUT_FILENO) != 0) ++ { ++ puts ("error: spawn_file_actions_adddup2 failed"); ++ exit (1); ++ } ++ ++ if (posix_spawn_file_actions_addclose (&a, pipefd[0]) != 0) ++ { ++ puts ("error: spawn_file_actions_addclose"); ++ exit (1); ++ } ++ ++ char *argv[] = { (char *) _PATH_BSHELL, (char *) "-c", (char *) "echo $$", ++ NULL }; ++ if (posix_spawn (&pid, _PATH_BSHELL, &a, NULL, argv, NULL) != 0) ++ { ++ puts ("error: spawn failed"); ++ exit (1); ++ } ++ ++ return NULL; ++} ++ ++ ++static int ++do_test (void) ++{ ++ /* The test basically pipe a 'echo $$' created by a thread with a ++ cancellation pending. It then checks if the thread is not cancelled, ++ the process is created and if the output is the expected one. */ ++ ++ if (pipe (pipefd) != 0) ++ { ++ puts ("error: pipe failed"); ++ exit (1); ++ } ++ ++ /* Not interested in knowing when the pipe is closed. */ ++ if (sigignore (SIGPIPE) != 0) ++ { ++ puts ("error: sigignore failed"); ++ exit (1); ++ } ++ ++ /* To synchronize with the thread. */ ++ if (pthread_barrier_init (&b, NULL, 2) != 0) ++ { ++ puts ("error: pthread_barrier_init failed"); ++ exit (1); ++ } ++ ++ pthread_t th; ++ if (pthread_create (&th, NULL, &tf, NULL) != 0) ++ { ++ puts ("error: pthread_create failed"); ++ exit (1); ++ } ++ ++ if (pthread_cancel (th) != 0) ++ { ++ puts ("error: pthread_cancel failed"); ++ exit (1); ++ } ++ ++ int r = pthread_barrier_wait (&b); ++ if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) ++ { ++ puts ("error: pthread_barrier_wait"); ++ exit (1); ++ } ++ ++ void *retval; ++ if (pthread_join (th, &retval) != 0) ++ { ++ puts ("error: pthread_join failed\n"); ++ } ++ if (retval == PTHREAD_CANCELED) ++ { ++ puts ("error: thread cancelled"); ++ exit (1); ++ } ++ ++ close (pipefd[1]); ++ ++ /* The global 'pid' should be set by thread posix_spawn calling. Check ++ below if it was executed correctly and with expected output. */ ++ ++ char buf[64]; ++ ssize_t n; ++ bool seen_pid = false; ++ while (TEMP_FAILURE_RETRY ((n = read (pipefd[0], buf, sizeof (buf)))) > 0) ++ { ++ /* We only expect to read the PID. */ ++ char *endp; ++ long int rpid = strtol (buf, &endp, 10); ++ ++ if (*endp != '\n') ++ { ++ printf ("error: didn't parse whole line: \"%s\"\n", buf); ++ exit (1); ++ } ++ if (endp == buf) ++ { ++ puts ("error: read empty line"); ++ exit (1); ++ } ++ ++ if (rpid != pid) ++ { ++ printf ("error: found \"%s\", expected PID %ld\n", buf, ++ (long int) pid); ++ exit (1); ++ } ++ ++ if (seen_pid) ++ { ++ puts ("error: found more than one PID line"); ++ exit (1); ++ } ++ ++ seen_pid = true; ++ } ++ ++ close (pipefd[0]); ++ ++ int status; ++ int err = waitpid (pid, &status, 0); ++ if (err != pid) ++ { ++ puts ("errnor: waitpid failed"); ++ exit (1); ++ } ++ ++ if (!seen_pid) ++ { ++ puts ("error: didn't get PID"); ++ exit (1); ++ } ++ ++ return 0; ++} +diff --git a/nptl/tst-once5.cc b/nptl/tst-once5.cc +index 978d8271bd..513ac53f6f 100644 +--- a/nptl/tst-once5.cc ++++ b/nptl/tst-once5.cc +@@ -75,5 +75,7 @@ do_test (void) + return result; + } + ++// The test currently hangs and is XFAILed. Reduce the timeout. ++#define TIMEOUT 1 + #define TEST_FUNCTION do_test () + #include "../test-skeleton.c" +diff --git a/nptl_db/structs.def b/nptl_db/structs.def +index a9b621b126..1cb6a46391 100644 +--- a/nptl_db/structs.def ++++ b/nptl_db/structs.def +@@ -48,7 +48,6 @@ DB_STRUCT (pthread) + DB_STRUCT_FIELD (pthread, list) + DB_STRUCT_FIELD (pthread, report_events) + DB_STRUCT_FIELD (pthread, tid) +-DB_STRUCT_FIELD (pthread, pid) + DB_STRUCT_FIELD (pthread, start_routine) + DB_STRUCT_FIELD (pthread, cancelhandling) + DB_STRUCT_FIELD (pthread, schedpolicy) +diff --git a/nptl_db/td_ta_thr_iter.c b/nptl_db/td_ta_thr_iter.c +index a990fed150..9e5059956b 100644 +--- a/nptl_db/td_ta_thr_iter.c ++++ b/nptl_db/td_ta_thr_iter.c +@@ -76,48 +76,28 @@ iterate_thread_list (td_thragent_t *ta, td_thr_iter_f *callback, + if (ps_pdread (ta->ph, addr, copy, ta->ta_sizeof_pthread) != PS_OK) + return TD_ERR; + +- /* Verify that this thread's pid field matches the child PID. +- If its pid field is negative, it's about to do a fork or it +- is the sole thread in a fork child. */ +- psaddr_t pid; +- err = DB_GET_FIELD_LOCAL (pid, ta, copy, pthread, pid, 0); +- if (err == TD_OK && (pid_t) (uintptr_t) pid < 0) +- { +- if (-(pid_t) (uintptr_t) pid == match_pid) +- /* It is about to do a fork, but is really still the parent PID. */ +- pid = (psaddr_t) (uintptr_t) match_pid; +- else +- /* It must be a fork child, whose new PID is in the tid field. */ +- err = DB_GET_FIELD_LOCAL (pid, ta, copy, pthread, tid, 0); +- } ++ err = DB_GET_FIELD_LOCAL (schedpolicy, ta, copy, pthread, ++ schedpolicy, 0); + if (err != TD_OK) + break; ++ err = DB_GET_FIELD_LOCAL (schedprio, ta, copy, pthread, ++ schedparam_sched_priority, 0); ++ if (err != TD_OK) ++ break; ++ ++ /* Now test whether this thread matches the specified conditions. */ + +- if ((pid_t) (uintptr_t) pid == match_pid) ++ /* Only if the priority level is as high or higher. */ ++ int descr_pri = ((uintptr_t) schedpolicy == SCHED_OTHER ++ ? 0 : (uintptr_t) schedprio); ++ if (descr_pri >= ti_pri) + { +- err = DB_GET_FIELD_LOCAL (schedpolicy, ta, copy, pthread, +- schedpolicy, 0); +- if (err != TD_OK) +- break; +- err = DB_GET_FIELD_LOCAL (schedprio, ta, copy, pthread, +- schedparam_sched_priority, 0); +- if (err != TD_OK) +- break; +- +- /* Now test whether this thread matches the specified conditions. */ +- +- /* Only if the priority level is as high or higher. */ +- int descr_pri = ((uintptr_t) schedpolicy == SCHED_OTHER +- ? 0 : (uintptr_t) schedprio); +- if (descr_pri >= ti_pri) +- { +- /* Yep, it matches. Call the callback function. */ +- td_thrhandle_t th; +- th.th_ta_p = (td_thragent_t *) ta; +- th.th_unique = addr; +- if (callback (&th, cbdata_p) != 0) +- return TD_DBERR; +- } ++ /* Yep, it matches. Call the callback function. */ ++ td_thrhandle_t th; ++ th.th_ta_p = (td_thragent_t *) ta; ++ th.th_unique = addr; ++ if (callback (&th, cbdata_p) != 0) ++ return TD_DBERR; + } + + /* Get the pointer to the next element. */ +diff --git a/nptl_db/td_thr_validate.c b/nptl_db/td_thr_validate.c +index f3c8a7bed6..9b89fecad2 100644 +--- a/nptl_db/td_thr_validate.c ++++ b/nptl_db/td_thr_validate.c +@@ -80,28 +80,5 @@ td_thr_validate (const td_thrhandle_t *th) + err = TD_OK; + } + +- if (err == TD_OK) +- { +- /* Verify that this is not a stale element in a fork child. */ +- pid_t match_pid = ps_getpid (th->th_ta_p->ph); +- psaddr_t pid; +- err = DB_GET_FIELD (pid, th->th_ta_p, th->th_unique, pthread, pid, 0); +- if (err == TD_OK && (pid_t) (uintptr_t) pid < 0) +- { +- /* This was a thread that was about to fork, or it is the new sole +- thread in a fork child. In the latter case, its tid was stored +- via CLONE_CHILD_SETTID and so is already the proper child PID. */ +- if (-(pid_t) (uintptr_t) pid == match_pid) +- /* It is about to do a fork, but is really still the parent PID. */ +- pid = (psaddr_t) (uintptr_t) match_pid; +- else +- /* It must be a fork child, whose new PID is in the tid field. */ +- err = DB_GET_FIELD (pid, th->th_ta_p, th->th_unique, +- pthread, tid, 0); +- } +- if (err == TD_OK && (pid_t) (uintptr_t) pid != match_pid) +- err = TD_NOTHR; +- } +- + return err; + } +diff --git a/po/de.po b/po/de.po +index 1383e8c4a9..ca14c7e386 100644 +--- a/po/de.po ++++ b/po/de.po +@@ -8,7 +8,7 @@ msgid "" + msgstr "" + "Project-Id-Version: GNU libc 2.22-pre1\n" + "POT-Creation-Date: 2015-07-31 00:10-0400\n" +-"PO-Revision-Date: 2015-08-31 18:30+0200\n" ++"PO-Revision-Date: 2016-04-22 18:44+0200\n" + "Last-Translator: Jochen Hein \n" + "Language-Team: German \n" + "Language: de\n" +@@ -4479,13 +4479,13 @@ msgstr "" + "%15s Cache ist dauerhaft\n" + "%15s Cache wird gemeinsam verwendet\n" + "%15Zu vorgeschlagene Größe\n" +-"%15Zu Gesamtröße des Data-Pools\n" ++"%15Zu Gesamtgröße des Data-Pools\n" + "%15Zu Benutzter Speicher im Data-Pool\n" + "%15lu Time to Live für positive Einträge in Sekunden\n" + "%15lu Time to Live für negative Einträge in Sekunden\n" + "%15 Cache-Hits bei positiven Einträgen\n" + "%15 Cache-Hits bei positiven Einträgen\n" +-"%15 Cache-Misses bei positiven Einträgen\n" ++"%15 Cache-Misses bei positiven Einträgen\n" + "%15 Cache-Misses bei negativen Einträgen\n" + "%15lu%% Cache-Hit Verhältnis\n" + "%15zu aktuelle Anzahl der Werte im Cache\n" +diff --git a/po/fi.po b/po/fi.po +index 17cb3e3e1d..8a2ab8358c 100644 +--- a/po/fi.po ++++ b/po/fi.po +@@ -24,16 +24,16 @@ + # + msgid "" + msgstr "" +-"Project-Id-Version: libc 2.21-pre1\n" ++"Project-Id-Version: libc 2.22-pre1\n" + "POT-Creation-Date: 2015-07-31 00:10-0400\n" +-"PO-Revision-Date: 2015-07-28 20:29+0300\n" ++"PO-Revision-Date: 2016-05-26 21:14+0300\n" + "Last-Translator: Lauri Nurmi \n" + "Language-Team: Finnish \n" + "Language: fi\n" + "MIME-Version: 1.0\n" + "Content-Type: text/plain; charset=UTF-8\n" + "Content-Transfer-Encoding: 8bit\n" +-"X-Generator: Poedit 1.8.3\n" ++"X-Generator: Poedit 1.8.7\n" + "Plural-Forms: nplurals=2; plural=(n != 1);\n" + + #: argp/argp-help.c:227 +@@ -126,7 +126,7 @@ msgid "%s%s%s:%u: %s%sUnexpected error: %s.\n" + msgstr "%s%s%s:%u: %s%sOdottamaton virhe: %s.\n" + + #: assert/assert.c:101 +-#, fuzzy, c-format ++#, c-format + msgid "" + "%s%s%s:%u: %s%sAssertion `%s' failed.\n" + "%n" +@@ -169,12 +169,12 @@ msgstr "" + #: malloc/memusagestat.c:563 nss/getent.c:973 nss/makedb.c:369 + #: posix/getconf.c:486 sunrpc/rpcinfo.c:691 + #: sysdeps/unix/sysv/linux/lddlibc4.c:61 +-#, fuzzy, c-format ++#, c-format + msgid "" + "For bug reporting instructions, please see:\n" + "%s.\n" + msgstr "" +-"Ohjeet ohjelmistovioista ilmoittamiseen ovat osoitteessa\n" ++"Katso ohjeet vikailmoitusten tekemiseen osoitteesta:\n" + "%s.\n" + + #: catgets/gencat.c:245 debug/pcprofiledump.c:225 debug/xtrace.sh:64 +@@ -321,9 +321,8 @@ msgstr "Käyttö: xtrace [VALITSIN]... OHJELMA [OHJELMANVALITSIN]...\\n" + + #: debug/xtrace.sh:32 elf/sotruss.sh:56 elf/sotruss.sh:67 elf/sotruss.sh:135 + #: malloc/memusage.sh:26 +-#, fuzzy + msgid "Try \\`%s --help' or \\`%s --usage' for more information.\\n" +-msgstr "Kokeile ”%s --help” tai ”%s --usage” saadaksesi lisää tietoa.\n" ++msgstr "Kokeile ”%s --help” tai ”%s --usage” saadaksesi lisää tietoa.\\n" + + #: debug/xtrace.sh:38 + #, fuzzy +@@ -594,9 +593,8 @@ msgid "cannot enable executable stack as shared object requires" + msgstr "jaettua objektikahvaa ei voi luoda" + + #: elf/dl-load.c:1339 +-#, fuzzy + msgid "cannot close file descriptor" +-msgstr "tiedostoa %s ei voi sulkea" ++msgstr "tiedostokahvaa ei voi sulkea" + + #: elf/dl-load.c:1568 + msgid "file too short" +@@ -796,9 +794,8 @@ msgid "Format to use: new, old or compat (default)" + msgstr "Käytettävä muoto: ”new”, ”old” tai ”compat” (oletus)" + + #: elf/ldconfig.c:151 +-#, fuzzy + msgid "Ignore auxiliary cache file" +-msgstr "Käytä CACHEa välimuistitiedostona" ++msgstr "Jätä huomiotta apuvälimuistitiedosto" + + #: elf/ldconfig.c:159 + msgid "Configure Dynamic Linker Run Time Bindings." +@@ -1087,9 +1084,9 @@ msgid "invalid process ID '%s'" + msgstr "virheellinen prosessi-ID ”%s”" + + #: elf/pldd.c:120 +-#, fuzzy, c-format ++#, c-format + msgid "cannot open %s" +-msgstr "laitetta %s ei voi avata" ++msgstr "tiedostoa %s ei voi avata" + + #: elf/pldd.c:152 + #, fuzzy, c-format +@@ -1102,24 +1099,24 @@ msgid "cannot prepare reading %s/task" + msgstr "ei voi avata laitetta %s lukutilaan" + + #: elf/pldd.c:168 +-#, fuzzy, c-format ++#, c-format + msgid "invalid thread ID '%s'" +-msgstr "virheellinen prosessi-ID ”%s”" ++msgstr "virheellinen säie-ID ”%s”" + + #: elf/pldd.c:179 +-#, fuzzy, c-format ++#, c-format + msgid "cannot attach to process %lu" +-msgstr "tiedostoa ”%s” ei voi avata" ++msgstr "ei voida kiinnittyä prosessiin %lu" + + #: elf/pldd.c:294 + #, c-format + msgid "cannot get information about process %lu" +-msgstr "" ++msgstr "tietojen saaminen prosessista %lu ei onnistu" + + #: elf/pldd.c:307 +-#, fuzzy, c-format ++#, c-format + msgid "process %lu is no ELF program" +-msgstr "ohjelma %lu ei ole käytettävissä\n" ++msgstr "prosessi %lu ei ole ELF-ohjelma" + + #: elf/readelflib.c:34 + #, c-format +@@ -1203,7 +1200,7 @@ msgstr "%s kohde ei saa olla hakemisto\n" + #: elf/sln.c:184 + #, c-format + msgid "%s: failed to remove the old destination\n" +-msgstr "" ++msgstr "%s: vanhan kohteen poistaminen epäonnistui\n" + + #: elf/sln.c:192 + #, c-format +@@ -1237,9 +1234,8 @@ msgid "Mandatory arguments to long options are also mandatory for any correspond + msgstr "Pakolliset argumentit pitkille valitsimille ovat pakollisia kaikille vastaaville lyhyille valitsimille.\\n" + + #: elf/sotruss.sh:55 +-#, fuzzy + msgid "%s: option requires an argument -- '%s'\\n" +-msgstr "%s: valitsin ”%s” vaatii argumentin\n" ++msgstr "%s: valitsin vaatii argumentin -- ”%c”\\n" + + #: elf/sotruss.sh:61 + msgid "%s: option is ambiguous; possibilities:" +@@ -1507,7 +1503,6 @@ msgid "unknown iconv() error %d" + msgstr "tuntematon iconv()-virhe %d" + + #: iconv/iconv_prog.c:791 +-#, fuzzy + msgid "" + "The following list contains all the coded character sets known. This does\n" + "not necessarily mean that all combinations of these names can be used for\n" +@@ -1516,9 +1511,9 @@ msgid "" + "\n" + " " + msgstr "" +-"Seuraavassa listassa ovat kaikki tunnetut koodatut merkistöt. Se ei\n" ++"Seuraavassa listassa ovat kaikki tunnetut koodatut merkistöt. Tämä ei\n" + "kuitenkaan välttämättä tarkoita sitä, että kaikkia näiden nimien\n" +-"yhdistelmiä voidaan käyttää FROM- ja TO-komentoriviparametreina. Yksi\n" ++"yhdistelmiä voisi käyttää FROM- ja TO-komentoriviparametreina. Yksi\n" + "koodattu merkistö voi olla listalla useilla eri nimillä (aliaksilla).\n" + "\n" + " " +@@ -2733,14 +2728,12 @@ msgid "locale.alias file to consult when making archive" + msgstr "Arkistoa luotaessa käytettävä locale.alias-tiedosto" + + #: locale/programs/localedef.c:150 +-#, fuzzy + msgid "Generate little-endian output" +-msgstr "Tuota little-endian-koodia" ++msgstr "Tuota little-endian-muotoa" + + #: locale/programs/localedef.c:152 +-#, fuzzy + msgid "Generate big-endian output" +-msgstr "Tuota big-endian-koodia" ++msgstr "Tuota big-endian-muotoa" + + #: locale/programs/localedef.c:157 + msgid "Compile locale specification" +@@ -4275,10 +4268,9 @@ msgid "" + msgstr "" + + #: nscd/nscd.c:635 +-#, fuzzy, c-format +-#| msgid "lstat failed" ++#, c-format + msgid "'wait' failed\n" +-msgstr "tiedoston tilan luku epäonnistui" ++msgstr "”wait” epäonnistui\n" + + #: nscd/nscd.c:642 + #, c-format +@@ -4670,9 +4662,9 @@ msgid "cannot create temporary file" + msgstr "tilapäistä tiedostoa ei voi luoda" + + #: nss/makedb.c:304 +-#, fuzzy, c-format ++#, c-format + msgid "cannot stat newly created file" +-msgstr "tiedoston ”%s” tilaa ei voi lukea: %s" ++msgstr "juuri luodun tiedoston tilaa ei voi lukea" + + #: nss/makedb.c:315 + #, c-format +@@ -4680,9 +4672,9 @@ msgid "cannot rename temporary file" + msgstr "tilapäistä tiedostoa ei voi nimetä uudelleen" + + #: nss/makedb.c:531 nss/makedb.c:554 +-#, fuzzy, c-format ++#, c-format + msgid "cannot create search tree" +-msgstr "hakupolulle ei voi luoda välimuistia" ++msgstr "hakupuuta ei voi luoda" + + #: nss/makedb.c:560 + msgid "duplicate key" +@@ -4699,9 +4691,9 @@ msgid "failed to write new database file" + msgstr "uuden tietokantatiedoston kirjoittaminen epäonnistui" + + #: nss/makedb.c:812 +-#, fuzzy, c-format ++#, c-format + msgid "cannot stat database file" +-msgstr "tiedoston ”%s” tilaa ei voi lukea: %s" ++msgstr "tietokantatiedoston tilaa ei voi lukea" + + #: nss/makedb.c:817 + #, fuzzy, c-format +@@ -4709,9 +4701,9 @@ msgid "cannot map database file" + msgstr "Karttatietokannassa ei ole enempää tietueita" + + #: nss/makedb.c:820 +-#, fuzzy, c-format ++#, c-format + msgid "file not a database file" +-msgstr "luettaessa profilointidatatiedoston tilaa" ++msgstr "tiedosto ei ole tietokantatiedosto" + + #: nss/makedb.c:871 + #, fuzzy, c-format +@@ -4726,7 +4718,7 @@ msgstr "Käyttö: %s [-v määrittely] muuttujanimi [polku]\n" + #: posix/getconf.c:403 + #, c-format + msgid " %s -a [pathname]\n" +-msgstr "" ++msgstr " %s -a [polku]\n" + + #: posix/getconf.c:479 + #, c-format +@@ -5094,11 +5086,11 @@ msgstr "Laitetta irrotettu" + + #: stdio-common/psiginfo.c:139 + msgid "Signal sent by kill()" +-msgstr "" ++msgstr "Signaalin lähetti kill()" + + #: stdio-common/psiginfo.c:142 + msgid "Signal sent by sigqueue()" +-msgstr "" ++msgstr "Signaalin lähetti sigqueue()" + + #: stdio-common/psiginfo.c:145 + msgid "Signal generated by the expiration of a timer" +@@ -5114,7 +5106,7 @@ msgstr "" + + #: stdio-common/psiginfo.c:157 + msgid "Signal sent by tkill()" +-msgstr "" ++msgstr "Signaalin lähetti tkill()" + + #: stdio-common/psiginfo.c:162 + msgid "Signal generated by the completion of an asynchronous name lookup request" +@@ -5296,9 +5288,8 @@ msgid "Failed (unspecified error)" + msgstr "Epäonnistui (määrittelemätön virhe)" + + #: sunrpc/clnt_raw.c:115 +-#, fuzzy + msgid "clnt_raw.c: fatal header serialization error" +-msgstr "clnt_raw.c: vakava otsikon serialisointivirhe" ++msgstr "clnt_raw.c: vakava otsikon sarjallistamisvirhe" + + #: sunrpc/pm_getmaps.c:77 + msgid "pmap_getmaps.c: rpc problem" +@@ -6825,9 +6816,8 @@ msgid "Interrupted by a signal" + msgstr "Signaalin keskeyttämä" + + #: sysdeps/posix/gai_strerror-strs.h:17 +-#, fuzzy + msgid "Parameter string not correctly encoded" +-msgstr "Parametrimerkkijono on väärin koodattu" ++msgstr "Parametrimerkkijono ei ole koodattu oikein" + + #: sysdeps/unix/sysv/linux/i386/readelflib.c:65 + #, c-format +diff --git a/po/sv.po b/po/sv.po +index 49d1f23904..e046577b08 100644 +--- a/po/sv.po ++++ b/po/sv.po +@@ -1,13 +1,17 @@ + # GNU libc message catalog for Swedish +-# Copyright © 1996, 1998, 2001, 2002, 2003, 2006, 2008, 2009, 2011, 2012, 2013, 2014, 2015 Free Software Foundation, Inc. ++# Copyright © 1996, 1998, 2001, 2002, 2003, 2006, 2008, 2009, 2011, 2012, 2013, 2014, 2015, 2016 Free Software Foundation, Inc. + # This file is distributed under the same license as the glibc package. +-# Jan Djärv , 1996, 1998, 2001, 2002, 2003, 2006, 2007, 2008, 2009, 2011, 2012, 2013, 2014, 2015 ++# ++# Jan Djärv , 1996, 1998, 2001, 2002, 2003, 2006, 2007, 2008, 2009, 2011, 2012, 2013, 2014, 2015. ++# Göran Uddeborg , 2016. ++# ++# $Revision: 1.3 $ + msgid "" + msgstr "" +-"Project-Id-Version: libc 2.21-pre1\n" ++"Project-Id-Version: libc 2.22-pre1\n" + "POT-Creation-Date: 2015-07-31 00:10-0400\n" +-"PO-Revision-Date: 2015-01-24 10:35+0100\n" +-"Last-Translator: Jan Djärv \n" ++"PO-Revision-Date: 2016-08-02 17:17+0200\n" ++"Last-Translator: Göran Uddeborg \n" + "Language-Team: Swedish \n" + "Language: sv\n" + "MIME-Version: 1.0\n" +@@ -48,7 +52,7 @@ msgstr " [FLAGGA...]" + #: argp/argp-help.c:1643 + #, c-format + msgid "Try `%s --help' or `%s --usage' for more information.\n" +-msgstr "Försök med \"%s --help\" eller \"%s --usage\" för mer information\n" ++msgstr "Försök med ”%s --help” eller ”%s --usage” för mer information.\n" + + #: argp/argp-help.c:1671 + #, c-format +@@ -304,11 +308,11 @@ msgstr "Användning: xtrace [FLAGGA]... PROGRAM [PROGRAMFLAGGA}...\\n" + #: debug/xtrace.sh:32 elf/sotruss.sh:56 elf/sotruss.sh:67 elf/sotruss.sh:135 + #: malloc/memusage.sh:26 + msgid "Try \\`%s --help' or \\`%s --usage' for more information.\\n" +-msgstr "Försök med \\\"%s --help\\\" eller \\\"%s --usage\\\" för mer information\\n" ++msgstr "Försök med ”%s --help” eller ”%s --usage” för mer information\\n" + + #: debug/xtrace.sh:38 + msgid "%s: option '%s' requires an argument.\\n" +-msgstr "%s: flaggan \\\"%s\\\" kräver ett argument\\n" ++msgstr "%s: flaggan ”%s” kräver ett argument.\\n" + + #: debug/xtrace.sh:45 + msgid "" +@@ -332,19 +336,17 @@ msgstr "" + " --usage Visa en kort hjälptext\n" + " -V,--version Visa versionsinformation och avsluta\n" + "\n" +-"Obligatoriska argument för långa flaggor är obligatoriska även för\n" ++"Obligatoriska argument för långa flaggor är obligatoriska även för\n" + "motsvarande korta.\n" + + #: debug/xtrace.sh:57 elf/ldd.bash.in:55 elf/sotruss.sh:49 + #: malloc/memusage.sh:64 + msgid "For bug reporting instructions, please see:\\\\n%s.\\\\n" +-msgstr "" +-"För felrapporteringsinstruktioner, se:\\\\n%s.\\\\n\n" +-"Rapportera fel eller synpunkter på översättningen till .\\\\n" ++msgstr "För felrapporteringsinstruktioner, se:\\\\n%s.\\\\nRapportera fel eller synpunkter på översättningen till:\\\\n.\\\\n" + + #: debug/xtrace.sh:125 + msgid "xtrace: unrecognized option \\`$1'\\n" +-msgstr "xtrace: okänd flagga \"$1\"\\n" ++msgstr "xtrace: okänd flagga ”$1”\\n" + + #: debug/xtrace.sh:138 + msgid "No program name given\\n" +@@ -353,12 +355,12 @@ msgstr "Inget programnamn givet\\n" + #: debug/xtrace.sh:146 + #, sh-format + msgid "executable \\`$program' not found\\n" +-msgstr "program \"$program\" hittades inte\\n" ++msgstr "program ”$program” hittades inte\\n" + + #: debug/xtrace.sh:150 + #, sh-format + msgid "\\`$program' is no executable\\n" +-msgstr "\"$program\" är inte en körbar binär\\n" ++msgstr "”$program” är inte en körbar binär\\n" + + #: dlfcn/dlinfo.c:63 + msgid "RTLD_SELF used in code not dynamically loaded" +@@ -396,7 +398,7 @@ msgstr ", OS ABI: %s %d.%d.%d" + #: elf/cache.c:157 elf/ldconfig.c:1340 + #, c-format + msgid "Can't open cache file %s\n" +-msgstr "Kan inte öppna cache-fil \"%s\"\n" ++msgstr "Kan inte öppna cache-filen %s\n" + + #: elf/cache.c:171 + #, c-format +@@ -416,7 +418,7 @@ msgstr "%d bibliotek hittades i cache \"%s\"\n" + #: elf/cache.c:426 + #, c-format + msgid "Can't create temporary cache file %s" +-msgstr "Kan inte skapa temporär cache-fil \"%s\"" ++msgstr "Kan inte skapa en temporär cache-fil %s" + + #: elf/cache.c:434 elf/cache.c:444 elf/cache.c:448 elf/cache.c:453 + #, c-format +@@ -829,7 +831,7 @@ msgstr "Kan inte ta status (lstat) på %s" + #: elf/ldconfig.c:609 + #, c-format + msgid "Ignored file %s since it is not a regular file." +-msgstr "Ignorerar fil %s eftersom den inte är en vanlig fil" ++msgstr "Ignorerar fil %s eftersom den inte är en vanlig fil." + + #: elf/ldconfig.c:618 + #, c-format +@@ -951,7 +953,7 @@ msgstr "" + + #: elf/ldd.bash.in:80 + msgid "ldd: option \\`$1' is ambiguous" +-msgstr "ldd: flaggan \"$1\" är tvetydig" ++msgstr "ldd: flaggan ”$1” är tvetydig" + + #: elf/ldd.bash.in:87 + msgid "unrecognized option" +@@ -959,7 +961,7 @@ msgstr "okänd flagga" + + #: elf/ldd.bash.in:88 elf/ldd.bash.in:125 + msgid "Try \\`ldd --help' for more information." +-msgstr "Försök med \"ldd --help\" för mer information" ++msgstr "Försök med \"ldd --help\" för mer information." + + #: elf/ldd.bash.in:124 + msgid "missing file arguments" +@@ -1028,10 +1030,9 @@ msgid "cannot read object name" + msgstr "kan inte läsa objektnamn" + + #: elf/pldd-xx.c:219 +-#, fuzzy, c-format +-#| msgid "cannot allocate memory for program header" ++#, c-format + msgid "cannot allocate buffer for object name" +-msgstr "kan inte allokera minne för programhuvud" ++msgstr "kan inte allokera en buffert för objektnamn" + + #: elf/pldd.c:64 + msgid "List dynamic shared objects loaded into process." +@@ -1212,11 +1213,11 @@ msgstr "" + + #: elf/sotruss.sh:46 + msgid "Mandatory arguments to long options are also mandatory for any corresponding\\nshort options.\\n" +-msgstr "Obligatoriska respektive valfria argument för långa flaggor är obligatoriska respektive\\nvalfria även för korta.\\n" ++msgstr "Obligatoriska respektive valfria argument för långa flaggor är obligatoriska\\nrespektive valfria även för korta.\\n" + + #: elf/sotruss.sh:55 + msgid "%s: option requires an argument -- '%s'\\n" +-msgstr "%s: flaggan kräver ett argument -- \\\"%s\\\"\\n" ++msgstr "%s: flaggan kräver ett argument — ”%s”\\n" + + #: elf/sotruss.sh:61 + msgid "%s: option is ambiguous; possibilities:" +@@ -1240,7 +1241,7 @@ msgstr "" + + #: elf/sotruss.sh:134 + msgid "%s: unrecognized option '%c%s'\\n" +-msgstr "%s: okänd flagga \\\"%c%s\\\"\\n" ++msgstr "%s: okänd flagga ”%c%s”\\n" + + #: elf/sprof.c:77 + msgid "Output selection:" +@@ -1260,7 +1261,7 @@ msgstr "generera anropsgraf" + + #: elf/sprof.c:89 + msgid "Read and display shared object profiling data." +-msgstr "Läs och visa profildata för delat objekt" ++msgstr "Läs och visa profildata för delat objekt." + + #: elf/sprof.c:94 + msgid "SHOBJ [PROFDATA]" +@@ -1622,7 +1623,7 @@ msgstr "Fel: .netrc kan läsas av andra." + + #: inet/ruserpass.c:185 + msgid "Remove password or make file unreadable by others." +-msgstr "Ta bort lösenord eller gör filen oläsbar för andra" ++msgstr "Ta bort lösenord eller gör filen oläsbar för andra." + + #: inet/ruserpass.c:277 + #, c-format +@@ -2182,12 +2183,12 @@ msgstr "Inget namn definierat i teckenuppsättning" + #: locale/programs/ld-ctype.c:479 + #, c-format + msgid "character L'\\u%0*x' in class `%s' must be in class `%s'" +-msgstr "tecken L\"\\u%0*x\" i klass \"%s\" måste vara i klass \"%s\"" ++msgstr "tecken L'\\u%0*x' i klassen ”%s” måste vara i klassen ”%s”" + + #: locale/programs/ld-ctype.c:494 + #, c-format + msgid "character L'\\u%0*x' in class `%s' must not be in class `%s'" +-msgstr "tecken L\"\\u%0*x\" i klass \"%s\" får inte vara i klass \"%s\"" ++msgstr "tecken L'\\u%0*x' i klassen ”%s” får inte vara i klassen ”%s”" + + #: locale/programs/ld-ctype.c:508 locale/programs/ld-ctype.c:566 + #, c-format +@@ -2611,7 +2612,7 @@ msgstr "Skriv mer information" + + #: locale/programs/locale.c:85 + msgid "Get locale-specific information." +-msgstr "Hämta lokalspecifik information" ++msgstr "Hämta lokalspecifik information." + + #: locale/programs/locale.c:88 + msgid "" +@@ -3022,7 +3023,7 @@ msgstr "felaktig mcheck_status, biblioteket är felaktigt\n" + + #: malloc/memusage.sh:32 + msgid "%s: option '%s' requires an argument\\n" +-msgstr "%s: flaggan \\\"%s\\\" kräver ett argument\\n" ++msgstr "%s: flaggan ”%s” kräver ett argument\\n" + + #: malloc/memusage.sh:38 + msgid "" +@@ -3091,11 +3092,11 @@ msgstr "" + + #: malloc/memusage.sh:191 + msgid "memusage: option \\`${1##*=}' is ambiguous" +-msgstr "memusage: flaggan \"${1##*=}\" är tvetydig" ++msgstr "memusage: flaggan ”${1##*=}” är tvetydig" + + #: malloc/memusage.sh:200 + msgid "memusage: unrecognized option \\`$1'" +-msgstr "memusage: okänd flagga \"$1\"" ++msgstr "memusage: okänd flagga ”$1”" + + #: malloc/memusage.sh:213 + msgid "No program name given" +@@ -3341,7 +3342,7 @@ msgstr "Kan inte skapa process hos server" + + #: nis/nis_error.h:48 + msgid "Master server busy, full dump rescheduled." +-msgstr "Huvudserver är upptagen, full dump åter schemalagd" ++msgstr "Huvudserver är upptagen, full dump åter schemalagd." + + #: nis/nis_local_names.c:121 + #, c-format +@@ -3511,7 +3512,7 @@ msgstr "\t\tRättigheter : " + + #: nis/nis_print.c:290 + msgid "Linked Object Type : " +-msgstr "Länkad objekttyp: " ++msgstr "Länkad objekttyp : " + + #: nis/nis_print.c:292 + #, c-format +@@ -3802,15 +3803,14 @@ msgid " (first)" + msgstr " (första)" + + #: nscd/cache.c:288 +-#, fuzzy, c-format +-#| msgid "cannot stat() file `%s': %s" ++#, c-format + msgid "checking for monitored file `%s': %s" +-msgstr "kan inte ta status på fil \"%s\": %s" ++msgstr "kontrollerar den övervakade filen ”%s”: %s" + + #: nscd/cache.c:298 + #, c-format + msgid "monitored file `%s` changed (mtime)" +-msgstr "" ++msgstr "den övervakade filen ”%s” ändrades (mtime)" + + #: nscd/cache.c:341 + #, c-format +@@ -3906,34 +3906,32 @@ msgstr "kan inte få uttag (socket) att acceptera förbindelser: %s" + #: nscd/connections.c:973 + #, c-format + msgid "disabled inotify-based monitoring for file `%s': %s" +-msgstr "" ++msgstr "avaktiverade inotify-baserad övervakning för filen ”%s”: %s" + + #: nscd/connections.c:977 + #, c-format + msgid "monitoring file `%s` (%d)" +-msgstr "" ++msgstr "övervakar filen ”%s” (%d)" + + #: nscd/connections.c:990 + #, c-format + msgid "disabled inotify-based monitoring for directory `%s': %s" +-msgstr "" ++msgstr "avaktiverade inotify-baserad övervakning av katalogen ”%s”: %s" + + #: nscd/connections.c:994 +-#, fuzzy, c-format +-#| msgid "Can't open directory %s" ++#, c-format + msgid "monitoring directory `%s` (%d)" +-msgstr "Kan inte öppna katalog %s" ++msgstr "övervakar katalogen ”%s” (%d)" + + #: nscd/connections.c:1022 +-#, fuzzy, c-format +-#| msgid "register trace file %s for database %s" ++#, c-format + msgid "monitoring file %s for database %s" +-msgstr "registrera spårningsfil %s för databas %s" ++msgstr "övervakar filen %s för databas %s" + + #: nscd/connections.c:1032 + #, c-format + msgid "stat failed for file `%s'; will try again later: %s" +-msgstr "" ++msgstr "stat misslyckades för filen ”%s”; kommer försöka igen senare: %s" + + #: nscd/connections.c:1151 + #, c-format +@@ -4032,44 +4030,42 @@ msgstr "handle_request: begäran mottagen (Version = %d)" + #: nscd/connections.c:1963 + #, c-format + msgid "ignored inotify event for `%s` (file exists)" +-msgstr "" ++msgstr "ignorerade inotify-händelse för ”%s” (filen finns)" + + #: nscd/connections.c:1968 + #, c-format + msgid "monitored file `%s` was %s, removing watch" +-msgstr "" ++msgstr "den övervakade filen ”%s” var %s, tar bort vakten" + + #: nscd/connections.c:1976 nscd/connections.c:2018 + #, c-format + msgid "failed to remove file watch `%s`: %s" +-msgstr "" ++msgstr "misslyckades att ta bort filvakt ”%s”: %s" + + #: nscd/connections.c:1991 + #, c-format + msgid "monitored file `%s` was written to" +-msgstr "" ++msgstr "den övervakade filen ”%s” skrevs till" + + #: nscd/connections.c:2015 + #, c-format + msgid "monitored parent directory `%s` was %s, removing watch on `%s`" +-msgstr "" ++msgstr "den övervakade föräldrakatalogen ”%s” var %s, tar bort vakten av ”%s”" + + #: nscd/connections.c:2041 + #, c-format + msgid "monitored file `%s` was %s, adding watch" +-msgstr "" ++msgstr "den övervakade filen ”%s” var %s, lägger till vakt" + + #: nscd/connections.c:2053 +-#, fuzzy, c-format +-#| msgid "failed to load shared object `%s'" ++#, c-format + msgid "failed to add file watch `%s`: %s" +-msgstr "misslyckades med att ladda delat objekt \"%s\"" ++msgstr "misslyckades med att lägga till filvakt ”%s”: %s" + + #: nscd/connections.c:2247 nscd/connections.c:2428 +-#, fuzzy, c-format +-#| msgid "disabled inotify after read error %d" ++#, c-format + msgid "disabled inotify-based monitoring after read error %d" +-msgstr "inaktiverade inotify efter läsfel %d" ++msgstr "avaktiverade inotify-baserad övervakning efter läsfel %d" + + #: nscd/connections.c:2543 + msgid "could not initialize conditional variable" +@@ -4199,7 +4195,7 @@ msgstr "Använd separat cache för varje användare" + + #: nscd/nscd.c:122 + msgid "Name Service Cache Daemon." +-msgstr "Namntjänst cache-demon" ++msgstr "Cache-demon för namntjänsten." + + #: nscd/nscd.c:155 nss/getent.c:1007 nss/makedb.c:206 + #, c-format +@@ -4531,11 +4527,11 @@ msgstr "Access Vector Cache (AVC) startad" + + #: nscd/selinux.c:368 + msgid "Error querying policy for undefined object classes or permissions." +-msgstr "Fel när policy för odefinierade objektklasser eller rättigheter hämtades" ++msgstr "Fel när policy för odefinierade objektklasser eller rättigheter hämtades." + + #: nscd/selinux.c:375 + msgid "Error getting security class for nscd." +-msgstr "Fel när säkerhetsklass för nscd hämtades" ++msgstr "Fel när säkerhetsklass för nscd hämtades." + + #: nscd/selinux.c:380 + #, c-format +@@ -4609,7 +4605,7 @@ msgstr "inaktivera DIN-kodning" + + #: nss/getent.c:64 + msgid "Get entries from administrative database." +-msgstr "Hämta poster från den administrativa databasen" ++msgstr "Hämta poster från den administrativa databasen." + + #: nss/getent.c:148 nss/getent.c:477 nss/getent.c:522 + #, c-format +@@ -4652,7 +4648,7 @@ msgstr "Genererad rad som inte ingår i iterationen" + + #: nss/makedb.c:131 + msgid "Create simple database from textual input." +-msgstr "Skapa en enkel databas från textuell indata" ++msgstr "Skapa en enkel databas från textuell indata." + + #: nss/makedb.c:134 + msgid "" +@@ -5412,7 +5408,7 @@ msgstr "Kan inte ange netid-flaggan utan TIRPC!\n" + #: sunrpc/rpc_main.c:1374 + #, c-format + msgid "Cannot use table flags with newstyle!\n" +-msgstr "Kan inte ange tabellflaggor med ny stil\n" ++msgstr "Kan inte ange tabellflaggor med ny stil!\n" + + #: sunrpc/rpc_main.c:1393 + #, c-format +@@ -7270,18 +7266,9 @@ msgstr "tidszonsförkortning skiljer sig från POSIX-standarden" + + #: timezone/zic.c:2789 + msgid "too many, or too long, time zone abbreviations" +-msgstr "för många eller för långa tidszonförkortningar" ++msgstr "för många eller för långa tidszonsförkortningar" + + #: timezone/zic.c:2829 + #, c-format + msgid "%s: Can't create directory %s: %s\n" + msgstr "%s: Kan inte skapa katalog %s: %s\n" +- +-#~ msgid "cannot load any more object with static TLS" +-#~ msgstr "kan inte ladda fler objekt med statiskt TLS" +- +-#~ msgid "%s: no PLTREL found in object %s\n" +-#~ msgstr "%s: hittade inga PLTREL i objekt %s\n" +- +-#~ msgid "cannot create internal descriptors" +-#~ msgstr "kan inte skapa interna deskriptorer" +diff --git a/posix/Makefile b/posix/Makefile +index 5b0e298f75..82a4020c76 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 \ +@@ -90,7 +90,7 @@ tests := tstgetopt testfnm runtests runptests \ + bug-getopt5 tst-getopt_long1 bug-regex34 bug-regex35 \ + tst-pathconf tst-getaddrinfo4 tst-rxspencer-no-utf8 \ + tst-fnmatch3 bug-regex36 tst-getaddrinfo5 \ +- tst-posix_spawn-fd ++ tst-posix_spawn-fd tst-glob-tilde + xtests := bug-ga2 + ifeq (yes,$(build-shared)) + test-srcs := globtest +@@ -133,7 +133,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 + +@@ -340,6 +341,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/execvpe.c b/posix/execvpe.c +index d933f9c92a..7cdb06a611 100644 +--- a/posix/execvpe.c ++++ b/posix/execvpe.c +@@ -48,12 +48,13 @@ maybe_script_execute (const char *file, char *const argv[], char *const envp[]) + } + } + +- /* Construct an argument list for the shell. */ ++ /* Construct an argument list for the shell. It will contain at minimum 3 ++ arguments (current shell, script, and an ending NULL. */ + char *new_argv[argc + 1]; + new_argv[0] = (char *) _PATH_BSHELL; + new_argv[1] = (char *) file; + if (argc > 1) +- memcpy (new_argv + 2, argv + 1, argc * sizeof(char *)); ++ memcpy (new_argv + 2, argv + 1, (argc - 1) * sizeof(char *)); + else + new_argv[2] = NULL; + +@@ -91,10 +92,11 @@ __execvpe (const char *file, char *const argv[], char *const envp[]) + /* Although GLIBC does not enforce NAME_MAX, we set it as the maximum + size to avoid unbounded stack allocation. Same applies for + PATH_MAX. */ +- size_t file_len = __strnlen (file, NAME_MAX + 1); ++ size_t file_len = __strnlen (file, NAME_MAX) + 1; + size_t path_len = __strnlen (path, PATH_MAX - 1) + 1; + +- if ((file_len > NAME_MAX) ++ /* NAME_MAX does not include the terminating null character. */ ++ if (((file_len-1) > NAME_MAX) + || !__libc_alloca_cutoff (path_len + file_len + 1)) + { + errno = ENAMETOOLONG; +@@ -103,6 +105,9 @@ __execvpe (const char *file, char *const argv[], char *const envp[]) + + const char *subp; + bool got_eacces = false; ++ /* The resulting string maximum size would be potentially a entry ++ in PATH plus '/' (path_len + 1) and then the the resulting file name ++ plus '\0' (file_len since it already accounts for the '\0'). */ + char buffer[path_len + file_len + 1]; + for (const char *p = path; ; p = subp) + { +@@ -123,7 +128,7 @@ __execvpe (const char *file, char *const argv[], char *const envp[]) + execute. */ + char *pend = mempcpy (buffer, p, subp - p); + *pend = '/'; +- memcpy (pend + (p < subp), file, file_len + 1); ++ memcpy (pend + (p < subp), file, file_len); + + __execve (buffer, argv, envp); + +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 ea4b0b61eb..f3fa807700 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; + +@@ -350,14 +351,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) + { + if (!(flags & GLOB_APPEND)) +@@ -377,11 +376,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); + return glob (pattern, flags & ~GLOB_BRACE, errfunc, pglob); + } +@@ -429,9 +426,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)) + { +@@ -450,9 +445,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) +@@ -489,14 +482,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) + { +@@ -521,11 +516,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), + } + + filename = pattern; +-#ifdef _AMIGA +- dirname = (char *) ""; +-#else + dirname = (char *) "."; +-#endif + dirlen = 0; + } + } +@@ -549,22 +540,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) +@@ -575,14 +565,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] == '\\') +@@ -615,7 +608,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] == '/' +@@ -625,100 +617,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 +@@ -733,26 +752,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') + { +@@ -767,8 +792,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 +@@ -792,12 +816,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; +@@ -819,7 +846,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 + { +@@ -836,11 +863,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 +@@ -856,7 +883,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; + } +@@ -864,20 +891,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 + { +@@ -890,32 +918,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); + } +@@ -936,7 +964,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 +@@ -944,8 +972,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; + } +@@ -957,24 +984,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. */ +@@ -993,19 +1020,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; +@@ -1019,12 +1045,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; +@@ -1034,7 +1067,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)); +@@ -1080,7 +1114,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; + } + +@@ -1091,19 +1128,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) +@@ -1118,7 +1142,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. */ +@@ -1129,13 +1154,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) +@@ -1147,28 +1173,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; +@@ -1180,7 +1206,8 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), + else + { + globfree (&dirs); +- return GLOB_NOMATCH; ++ retval = GLOB_NOMATCH; ++ goto out; + } + } + +@@ -1226,7 +1253,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) +@@ -1238,7 +1266,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; + } + } + } +@@ -1263,7 +1292,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; +@@ -1289,32 +1319,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; +@@ -1335,28 +1345,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 +@@ -1364,7 +1370,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) +@@ -1374,7 +1380,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]); +@@ -1384,103 +1390,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). */ +@@ -1491,25 +1451,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))) +@@ -1529,14 +1489,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; + } +@@ -1544,9 +1506,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; +@@ -1568,16 +1532,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) +@@ -1597,19 +1555,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)) + { +@@ -1617,10 +1580,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)) +@@ -1636,6 +1602,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; + } + } + } +@@ -1646,29 +1614,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: +@@ -1684,7 +1650,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; +@@ -1710,7 +1676,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 a5f5a7f9e2..39e54afe8b 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/sysdeps/unix/sysv/linux/sh/pread.c b/posix/globfree64.c +similarity index 68% +rename from sysdeps/unix/sysv/linux/sh/pread.c +rename to posix/globfree64.c +index d3f99f35db..c9f8908a4e 100644 +--- a/sysdeps/unix/sysv/linux/sh/pread.c ++++ b/posix/globfree64.c +@@ -1,6 +1,6 @@ +-/* Copyright (C) 1997-2016 Free Software Foundation, Inc. ++/* 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. +- Contributed by Ulrich Drepper , 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public +@@ -16,8 +16,16 @@ + License along with the GNU C Library; if not, see + . */ + +-/* SH4 ABI does not really require argument alignment for 64-bits, but +- the kernel interface for pread adds a dummy long argument before the +- offset. */ +-#define __ALIGNMENT_ARG +-#include ++#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/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 8be41d3ae1..a4c86b9762 100644 +--- a/resolv/Makefile ++++ b/resolv/Makefile +@@ -40,6 +40,9 @@ ifeq ($(have-thread-library),yes) + extra-libs += libanl + routines += gai_sigqueue + tests += tst-res_hconf_reorder ++ ++# This test sends millions of packets and is rather slow. ++xtests += tst-resolv-qtypes + endif + extra-libs-others = $(extra-libs) + libresolv-routines := gethnamaddr res_comp res_debug \ +@@ -117,3 +120,5 @@ tst-leaks2-ENV = MALLOC_TRACE=$(objpfx)tst-leaks2.mtrace + $(objpfx)mtrace-tst-leaks2.out: $(objpfx)tst-leaks2.out + $(common-objpfx)malloc/mtrace $(objpfx)tst-leaks2.mtrace > $@; \ + $(evaluate-test) ++ ++$(objpfx)tst-resolv-qtypes: $(objpfx)libresolv.so $(shared-thread-library) +diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c +index 5f9e35701b..d16fa4b8ed 100644 +--- a/resolv/nss_dns/dns-host.c ++++ b/resolv/nss_dns/dns-host.c +@@ -323,7 +323,7 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, + + int olderr = errno; + enum nss_status status; +- int n = __libc_res_nsearch (&_res, name, C_IN, T_UNSPEC, ++ int n = __libc_res_nsearch (&_res, name, C_IN, T_QUERY_A_AND_AAAA, + host_buffer.buf->buf, 2048, &host_buffer.ptr, + &ans2p, &nans2p, &resplen2, &ans2p_malloced); + if (n >= 0) +diff --git a/resolv/res_mkquery.c b/resolv/res_mkquery.c +index 12f9730199..d80b5318e5 100644 +--- a/resolv/res_mkquery.c ++++ b/resolv/res_mkquery.c +@@ -103,6 +103,10 @@ res_nmkquery(res_state statp, + int n; + u_char *dnptrs[20], **dpp, **lastdnptr; + ++ if (class < 0 || class > 65535 ++ || type < 0 || type > 65535) ++ return -1; ++ + #ifdef DEBUG + if (statp->options & RES_DEBUG) + printf(";; res_nmkquery(%s, %s, %s, %s)\n", +diff --git a/resolv/res_query.c b/resolv/res_query.c +index 944d1a90f5..07dc6f6583 100644 +--- a/resolv/res_query.c ++++ b/resolv/res_query.c +@@ -122,7 +122,7 @@ __libc_res_nquery(res_state statp, + int n, use_malloc = 0; + u_int oflags = statp->_flags; + +- size_t bufsize = (type == T_UNSPEC ? 2 : 1) * QUERYSIZE; ++ size_t bufsize = (type == T_QUERY_A_AND_AAAA ? 2 : 1) * QUERYSIZE; + u_char *buf = alloca (bufsize); + u_char *query1 = buf; + int nquery1 = -1; +@@ -137,7 +137,7 @@ __libc_res_nquery(res_state statp, + printf(";; res_query(%s, %d, %d)\n", name, class, type); + #endif + +- if (type == T_UNSPEC) ++ if (type == T_QUERY_A_AND_AAAA) + { + n = res_nmkquery(statp, QUERY, name, class, T_A, NULL, 0, NULL, + query1, bufsize); +@@ -190,7 +190,7 @@ __libc_res_nquery(res_state statp, + if (__builtin_expect (n <= 0, 0) && !use_malloc) { + /* Retry just in case res_nmkquery failed because of too + short buffer. Shouldn't happen. */ +- bufsize = (type == T_UNSPEC ? 2 : 1) * MAXPACKET; ++ bufsize = (type == T_QUERY_A_AND_AAAA ? 2 : 1) * MAXPACKET; + buf = malloc (bufsize); + if (buf != NULL) { + query1 = buf; +diff --git a/resolv/tst-resolv-qtypes.c b/resolv/tst-resolv-qtypes.c +new file mode 100644 +index 0000000000..b3e60c693b +--- /dev/null ++++ b/resolv/tst-resolv-qtypes.c +@@ -0,0 +1,185 @@ ++/* Exercise low-level query functions with different QTYPEs. ++ Copyright (C) 2016 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 ++ ++/* If ture, the response function will send the actual response packet ++ over TCP instead of UDP. */ ++static volatile bool force_tcp; ++ ++/* Send back a fake resource record matching the QTYPE. */ ++static void ++response (const struct resolv_response_context *ctx, ++ struct resolv_response_builder *b, ++ const char *qname, uint16_t qclass, uint16_t qtype) ++{ ++ if (force_tcp && ctx->tcp) ++ { ++ resolv_response_init (b, (struct resolv_response_flags) { .tc = 1 }); ++ resolv_response_add_question (b, qname, qclass, qtype); ++ return; ++ } ++ ++ resolv_response_init (b, (struct resolv_response_flags) { }); ++ resolv_response_add_question (b, qname, qclass, qtype); ++ resolv_response_section (b, ns_s_an); ++ resolv_response_open_record (b, qname, qclass, qtype, 0); ++ resolv_response_add_data (b, &qtype, sizeof (qtype)); ++ resolv_response_close_record (b); ++} ++ ++static const const char *domain = "www.example.com"; ++ ++static int ++wrap_res_query (int type, unsigned char *answer, int answer_length) ++{ ++ return res_query (domain, C_IN, type, answer, answer_length); ++} ++ ++static int ++wrap_res_search (int type, unsigned char *answer, int answer_length) ++{ ++ return res_query (domain, C_IN, type, answer, answer_length); ++} ++ ++static int ++wrap_res_querydomain (int type, unsigned char *answer, int answer_length) ++{ ++ return res_querydomain ("www", "example.com", C_IN, type, ++ answer, answer_length); ++} ++ ++static int ++wrap_res_send (int type, unsigned char *answer, int answer_length) ++{ ++ unsigned char buf[512]; ++ int ret = res_mkquery (QUERY, domain, C_IN, type, ++ (const unsigned char *) "", 0, NULL, ++ buf, sizeof (buf)); ++ if (type < 0 || type >= 65536) ++ { ++ /* res_mkquery fails for out-of-range record types. */ ++ TEST_VERIFY_EXIT (ret == -1); ++ return -1; ++ } ++ TEST_VERIFY_EXIT (ret > 12); /* DNS header length. */ ++ return res_send (buf, ret, answer, answer_length); ++} ++ ++static int ++wrap_res_nquery (int type, unsigned char *answer, int answer_length) ++{ ++ return res_nquery (&_res, domain, C_IN, type, answer, answer_length); ++} ++ ++static int ++wrap_res_nsearch (int type, unsigned char *answer, int answer_length) ++{ ++ return res_nquery (&_res, domain, C_IN, type, answer, answer_length); ++} ++ ++static int ++wrap_res_nquerydomain (int type, unsigned char *answer, int answer_length) ++{ ++ return res_nquerydomain (&_res, "www", "example.com", C_IN, type, ++ answer, answer_length); ++} ++ ++static int ++wrap_res_nsend (int type, unsigned char *answer, int answer_length) ++{ ++ unsigned char buf[512]; ++ int ret = res_nmkquery (&_res, QUERY, domain, C_IN, type, ++ (const unsigned char *) "", 0, NULL, ++ buf, sizeof (buf)); ++ if (type < 0 || type >= 65536) ++ { ++ /* res_mkquery fails for out-of-range record types. */ ++ TEST_VERIFY_EXIT (ret == -1); ++ return -1; ++ } ++ TEST_VERIFY_EXIT (ret > 12); /* DNS header length. */ ++ return res_nsend (&_res, buf, ret, answer, answer_length); ++} ++ ++static void ++test_function (const char *fname, ++ int (*func) (int type, ++ unsigned char *answer, int answer_length)) ++{ ++ unsigned char buf[512]; ++ for (int tcp = 0; tcp < 2; ++tcp) ++ { ++ force_tcp = tcp; ++ for (unsigned int type = 1; type <= 65535; ++type) ++ { ++ if (test_verbose) ++ printf ("info: sending QTYPE %d with %s (tcp=%d)\n", ++ type, fname, tcp); ++ int ret = func (type, buf, sizeof (buf)); ++ if (ret != 47) ++ FAIL_EXIT1 ("%s tcp=%d qtype=%d return value %d", ++ fname,tcp, type, ret); ++ /* One question, one answer record. */ ++ TEST_VERIFY (memcmp (buf + 4, "\0\1\0\1\0\0\0\0", 8) == 0); ++ /* Question section. */ ++ static const char qname[] = "\3www\7example\3com"; ++ size_t qname_length = sizeof (qname); ++ TEST_VERIFY (memcmp (buf + 12, qname, qname_length) == 0); ++ /* RDATA part of answer. */ ++ uint16_t type16 = type; ++ TEST_VERIFY (memcmp (buf + ret - 2, &type16, sizeof (type16)) == 0); ++ } ++ } ++ ++ TEST_VERIFY (func (-1, buf, sizeof (buf) == -1)); ++ TEST_VERIFY (func (65536, buf, sizeof (buf) == -1)); ++} ++ ++static int ++do_test (void) ++{ ++ struct resolv_redirect_config config = ++ { ++ .response_callback = response, ++ }; ++ struct resolv_test *obj = resolv_test_start (config); ++ ++ test_function ("res_query", &wrap_res_query); ++ test_function ("res_search", &wrap_res_search); ++ test_function ("res_querydomain", &wrap_res_querydomain); ++ test_function ("res_send", &wrap_res_send); ++ ++ test_function ("res_nquery", &wrap_res_nquery); ++ test_function ("res_nsearch", &wrap_res_nsearch); ++ test_function ("res_nquerydomain", &wrap_res_nquerydomain); ++ test_function ("res_nsend", &wrap_res_nsend); ++ ++ resolv_test_end (obj); ++ return 0; ++} ++ ++#define TIMEOUT 300 ++#include +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/sunrpc/Makefile b/sunrpc/Makefile +index 789ef423e5..1e91905011 100644 +--- a/sunrpc/Makefile ++++ b/sunrpc/Makefile +@@ -96,13 +96,18 @@ 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 + xtests := tst-getmyaddr + + ifeq ($(have-thread-library),yes) + xtests += thrsvc + endif + ++ifeq ($(run-built-tests),yes) ++rpcgen-tests := $(objpfx)bug20790.out ++tests-special += $(rpcgen-tests) ++endif ++ + headers += $(rpcsvc:%.x=rpcsvc/%.h) + extra-libs := librpcsvc + extra-libs-others := librpcsvc # Make it in `others' pass, not `lib' pass. +@@ -153,6 +158,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)) + +@@ -225,3 +231,9 @@ endif + endif + + $(objpfx)thrsvc: $(common-objpfx)linkobj/libc.so $(shared-thread-library) ++ ++ifeq ($(run-built-tests),yes) ++$(rpcgen-tests): $(objpfx)%.out: %.x $(objpfx)rpcgen ++ $(built-program-cmd) -c $< -o $@; \ ++ $(evaluate-test) ++endif +diff --git a/sunrpc/bug20790.x b/sunrpc/bug20790.x +new file mode 100644 +index 0000000000..a00c9b3830 +--- /dev/null ++++ b/sunrpc/bug20790.x +@@ -0,0 +1 @@ ++program TPROG { version TVERS { int FUNC(int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) = 1; } = 1; } = 1; +diff --git a/sunrpc/clnt_udp.c b/sunrpc/clnt_udp.c +index 4d9acb1e6a..1de25cb771 100644 +--- a/sunrpc/clnt_udp.c ++++ b/sunrpc/clnt_udp.c +@@ -421,9 +421,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); +diff --git a/sunrpc/rpc_parse.c b/sunrpc/rpc_parse.c +index 1a1df6d8c2..505a6554cf 100644 +--- a/sunrpc/rpc_parse.c ++++ b/sunrpc/rpc_parse.c +@@ -521,7 +521,7 @@ static void + get_prog_declaration (declaration * dec, defkind dkind, int num /* arg number */ ) + { + token tok; +- char name[10]; /* argument name */ ++ char name[MAXLINESIZE]; /* argument name */ + + if (dkind == DEF_PROGRAM) + { +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/support/Makefile b/support/Makefile +new file mode 100644 +index 0000000000..20b0343ade +--- /dev/null ++++ b/support/Makefile +@@ -0,0 +1,146 @@ ++# Makefile for support library, used only at build and test time ++# 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 ++# . ++ ++subdir := support ++ ++include ../Makeconfig ++ ++extra-libs := libsupport ++extra-libs-others = $(extra-libs) ++extra-libs-noinstall := $(extra-libs) ++ ++libsupport-routines = \ ++ check \ ++ check_addrinfo \ ++ check_dns_packet \ ++ check_hostent \ ++ check_netent \ ++ delayed_exit \ ++ ignore_stderr \ ++ oom_error \ ++ resolv_test \ ++ set_fortify_handler \ ++ support-xstat \ ++ support_become_root \ ++ support_can_chroot \ ++ support_capture_subprocess \ ++ support_capture_subprocess_check \ ++ support_enter_network_namespace \ ++ support_format_address_family \ ++ support_format_addrinfo \ ++ support_format_dns_packet \ ++ 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 \ ++ xdup2 \ ++ xfclose \ ++ xfopen \ ++ xfork \ ++ xgetsockname \ ++ xlisten \ ++ xmalloc \ ++ xmemstream \ ++ xmkdir \ ++ xmmap \ ++ xmunmap \ ++ xopen \ ++ xpipe \ ++ xpoll \ ++ xpthread_attr_destroy \ ++ xpthread_attr_init \ ++ xpthread_attr_setdetachstate \ ++ xpthread_attr_setstacksize \ ++ xpthread_barrier_destroy \ ++ xpthread_barrier_init \ ++ xpthread_barrier_wait \ ++ xpthread_cancel \ ++ xpthread_check_return \ ++ xpthread_cond_wait \ ++ xpthread_create \ ++ xpthread_detach \ ++ xpthread_join \ ++ xpthread_mutex_consistent \ ++ xpthread_mutex_destroy \ ++ xpthread_mutex_init \ ++ xpthread_mutex_lock \ ++ xpthread_mutex_unlock \ ++ xpthread_mutexattr_destroy \ ++ xpthread_mutexattr_init \ ++ xpthread_mutexattr_setprotocol \ ++ xpthread_mutexattr_setpshared \ ++ xpthread_mutexattr_setrobust \ ++ xpthread_mutexattr_settype \ ++ xpthread_once \ ++ xpthread_sigmask \ ++ xpthread_spin_lock \ ++ xpthread_spin_unlock \ ++ xrealloc \ ++ xrecvfrom \ ++ xsendto \ ++ xsetsockopt \ ++ xsocket \ ++ xstrdup \ ++ xwaitpid \ ++ xwrite \ ++ ++libsupport-static-only-routines := $(libsupport-routines) ++# Only build one variant of the library. ++libsupport-inhibit-o := .os ++ifeq ($(build-shared),yes) ++libsupport-inhibit-o += .o ++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) ++tests-special = \ ++ $(objpfx)tst-support_record_failure-2.out ++ ++$(objpfx)tst-support_record_failure-2.out: tst-support_record_failure-2.sh \ ++ $(objpfx)tst-support_record_failure ++ $(SHELL) $< $(common-objpfx) '$(test-program-prefix-before-env)' \ ++ '$(run-program-env)' '$(test-program-prefix-after-env)' \ ++ > $@; \ ++ $(evaluate-test) ++endif ++ ++$(objpfx)tst-support_format_dns_packet: $(common-objpfx)resolv/libresolv.so ++ ++include ../Rules +diff --git a/support/README b/support/README +new file mode 100644 +index 0000000000..476cfcda59 +--- /dev/null ++++ b/support/README +@@ -0,0 +1,29 @@ ++This subdirectory contains infrastructure which is not put into ++installed libraries, but may be linked into programs (installed or ++not) and tests. ++ ++# Error-checking wrappers ++ ++These wrappers test for error return codes an terminate the process on ++error. They are declared in these header files: ++ ++* support.h ++* xsignal.h ++* xthread.h ++ ++In general, new wrappers should be added to support.h if possible. ++However, support.h must remain fully compatible with C90 and therefore ++cannot include headers which use identifers not reserved in C90. If ++the wrappers need additional types, additional headers such as ++signal.h need to be introduced. ++ ++# Test framework ++ ++The test framework provides a main program for tests, including a ++timeout for hanging tests. See README-testing.c for a minimal ++example, and test-driver.c for details how to use it. The following ++header files provide related declarations: ++ ++* check.h ++* temp_file.h ++* test-driver.h +diff --git a/support/README-testing.c b/support/README-testing.c +new file mode 100644 +index 0000000000..9d289c3020 +--- /dev/null ++++ b/support/README-testing.c +@@ -0,0 +1,19 @@ ++/* This file contains an example test case which shows minimal use of ++ the test framework. Additional testing hooks are described in ++ . */ ++ ++/* This function will be called from the test driver. */ ++static int ++do_test (void) ++{ ++ if (3 == 5) ++ /* Indicate failure. */ ++ return 1; ++ else ++ /* Indicate success. */ ++ return 0; ++} ++ ++/* This file references do_test above and contains the definition of ++ the main function. */ ++#include +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.c b/support/check.c +new file mode 100644 +index 0000000000..592f2bc856 +--- /dev/null ++++ b/support/check.c +@@ -0,0 +1,57 @@ ++/* Support code for reporting test results. ++ 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 ++ ++static void ++print_failure (const char *file, int line, const char *format, va_list ap) ++{ ++ printf ("error: %s:%d: ", file, line); ++ vprintf (format, ap); ++ puts (""); ++} ++ ++int ++support_print_failure_impl (const char *file, int line, ++ const char *format, ...) ++{ ++ support_record_failure (); ++ va_list ap; ++ va_start (ap, format); ++ print_failure (file, line, format, ap); ++ va_end (ap); ++ return 1; ++} ++ ++void ++support_exit_failure_impl (int status, const char *file, int line, ++ const char *format, ...) ++{ ++ if (status != EXIT_SUCCESS && status != EXIT_UNSUPPORTED) ++ support_record_failure (); ++ va_list ap; ++ va_start (ap, format); ++ print_failure (file, line, format, ap); ++ va_end (ap); ++ exit (status); ++} +diff --git a/support/check.h b/support/check.h +new file mode 100644 +index 0000000000..1d244a3557 +--- /dev/null ++++ b/support/check.h +@@ -0,0 +1,94 @@ ++/* Functionality for reporting test results. ++ 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 ++ . */ ++ ++#ifndef SUPPORT_CHECK_H ++#define SUPPORT_CHECK_H ++ ++#include ++ ++__BEGIN_DECLS ++ ++/* Record a test failure, print the failure message to standard output ++ and return 1. */ ++#define FAIL_RET(...) \ ++ return support_print_failure_impl (__FILE__, __LINE__, __VA_ARGS__) ++ ++/* Print the failure message and terminate the process with STATUS. ++ Record a the process as failed if STATUS is neither EXIT_SUCCESS ++ nor EXIT_UNSUPPORTED. */ ++#define FAIL_EXIT(status, ...) \ ++ support_exit_failure_impl (status, __FILE__, __LINE__, __VA_ARGS__) ++ ++/* Record a test failure, print the failure message and terminate with ++ exit status 1. */ ++#define FAIL_EXIT1(...) \ ++ support_exit_failure_impl (1, __FILE__, __LINE__, __VA_ARGS__) ++ ++/* Print failure message and terminate with as unsupported test (exit ++ status of 77). */ ++#define FAIL_UNSUPPORTED(...) \ ++ support_exit_failure_impl (77, __FILE__, __LINE__, __VA_ARGS__) ++ ++/* Record a test failure (but continue executing) if EXPR evaluates to ++ false. */ ++#define TEST_VERIFY(expr) \ ++ ({ \ ++ if (expr) \ ++ ; \ ++ else \ ++ support_test_verify_impl (-1, __FILE__, __LINE__, #expr); \ ++ }) ++ ++/* Record a test failure and exit if EXPR evaluates to false. */ ++#define TEST_VERIFY_EXIT(expr) \ ++ ({ \ ++ if (expr) \ ++ ; \ ++ else \ ++ support_test_verify_impl (1, __FILE__, __LINE__, #expr); \ ++ }) ++ ++int support_print_failure_impl (const char *file, int line, ++ const char *format, ...) ++ __attribute__ ((nonnull (1), format (printf, 3, 4))); ++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, ++ const char *expr); ++ ++/* Record a test failure. This function returns and does not ++ terminate the process. The failure counter is stored in a shared ++ memory mapping, so that failures reported in child processes are ++ visible to the parent process and test driver. This function ++ depends on initialization by an ELF constructor, so it can only be ++ invoked after the test driver has run. Note that this function ++ does not support reporting failures from a DSO. */ ++void support_record_failure (void); ++ ++/* Internal function called by the test driver. */ ++int support_report_failure (int status) ++ __attribute__ ((weak, warn_unused_result)); ++ ++/* Internal function used to test the failure recording framework. */ ++void support_record_failure_reset (void); ++ ++__END_DECLS ++ ++#endif /* SUPPORT_CHECK_H */ +diff --git a/support/check_addrinfo.c b/support/check_addrinfo.c +new file mode 100644 +index 0000000000..55895ace3c +--- /dev/null ++++ b/support/check_addrinfo.c +@@ -0,0 +1,42 @@ ++/* Compare struct addrinfo values against a formatted string. ++ 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 ++ ++void ++check_addrinfo (const char *query_description, struct addrinfo *ai, int ret, ++ const char *expected) ++{ ++ char *formatted = support_format_addrinfo (ai, ret); ++ if (strcmp (formatted, expected) != 0) ++ { ++ support_record_failure (); ++ printf ("error: addrinfo comparison failure\n"); ++ if (query_description != NULL) ++ printf ("query: %s\n", query_description); ++ support_run_diff ("expected", expected, ++ "actual", formatted); ++ } ++ free (formatted); ++} +diff --git a/support/check_dns_packet.c b/support/check_dns_packet.c +new file mode 100644 +index 0000000000..d2a31bed7b +--- /dev/null ++++ b/support/check_dns_packet.c +@@ -0,0 +1,42 @@ ++/* Check that a DNS packet buffer has the expected contents. ++ 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 ++ ++void ++check_dns_packet (const char *query_description, ++ const unsigned char *buffer, size_t length, ++ const char *expected) ++{ ++ char *formatted = support_format_dns_packet (buffer, length); ++ if (strcmp (formatted, expected) != 0) ++ { ++ support_record_failure (); ++ printf ("error: packet comparison failure\n"); ++ if (query_description != NULL) ++ printf ("query: %s\n", query_description); ++ support_run_diff ("expected", expected, "actual", formatted); ++ } ++ free (formatted); ++} +diff --git a/support/check_hostent.c b/support/check_hostent.c +new file mode 100644 +index 0000000000..890d672d50 +--- /dev/null ++++ b/support/check_hostent.c +@@ -0,0 +1,42 @@ ++/* Compare struct hostent values against a formatted string. ++ 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 ++ ++void ++check_hostent (const char *query_description, struct hostent *h, ++ const char *expected) ++{ ++ char *formatted = support_format_hostent (h); ++ if (strcmp (formatted, expected) != 0) ++ { ++ support_record_failure (); ++ printf ("error: hostent comparison failure\n"); ++ if (query_description != NULL) ++ printf ("query: %s\n", query_description); ++ support_run_diff ("expected", expected, ++ "actual", formatted); ++ } ++ free (formatted); ++} +diff --git a/support/check_netent.c b/support/check_netent.c +new file mode 100644 +index 0000000000..daa3083fd1 +--- /dev/null ++++ b/support/check_netent.c +@@ -0,0 +1,42 @@ ++/* Compare struct netent values against a formatted string. ++ 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 ++ ++void ++check_netent (const char *query_description, struct netent *e, ++ const char *expected) ++{ ++ char *formatted = support_format_netent (e); ++ if (strcmp (formatted, expected) != 0) ++ { ++ support_record_failure (); ++ printf ("error: netent comparison failure\n"); ++ if (query_description != NULL) ++ printf ("query: %s\n", query_description); ++ support_run_diff ("expected", expected, ++ "actual", formatted); ++ } ++ free (formatted); ++} +diff --git a/support/check_nss.h b/support/check_nss.h +new file mode 100644 +index 0000000000..2893f2c295 +--- /dev/null ++++ b/support/check_nss.h +@@ -0,0 +1,42 @@ ++/* Test verification functions for NSS- and DNS-related data. ++ 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 ++ . */ ++ ++#ifndef SUPPORT_CHECK_NSS_H ++#define SUPPORT_CHECK_NSS_H ++ ++#include ++#include ++ ++__BEGIN_DECLS ++ ++/* Compare the data structures against the expected values (which have ++ to be formatted according to the support_format_* functions in ++ ). If there is a difference, a delayed test ++ failure is recorded, and a diff is written to standard output. */ ++void check_addrinfo (const char *query_description, ++ struct addrinfo *, int ret, const char *expected); ++void check_dns_packet (const char *query_description, ++ const unsigned char *, size_t, const char *expected); ++void check_hostent (const char *query_description, ++ struct hostent *, const char *expected); ++void check_netent (const char *query_description, ++ struct netent *, const char *expected); ++ ++__END_DECLS ++ ++#endif /* SUPPORT_CHECK_NSS_H */ +diff --git a/support/delayed_exit.c b/support/delayed_exit.c +new file mode 100644 +index 0000000000..67442f95df +--- /dev/null ++++ b/support/delayed_exit.c +@@ -0,0 +1,55 @@ ++/* Time-triggered process termination. ++ 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 ++ ++static void * ++delayed_exit_thread (void *seconds_as_ptr) ++{ ++ int seconds = (uintptr_t) seconds_as_ptr; ++ struct timespec delay = { seconds, 0 }; ++ struct timespec remaining = { 0 }; ++ if (nanosleep (&delay, &remaining) != 0) ++ FAIL_EXIT1 ("nanosleep: %m"); ++ /* Exit the process sucessfully. */ ++ exit (0); ++ return NULL; ++} ++ ++void ++delayed_exit (int seconds) ++{ ++ /* Create the new thread with all signals blocked. */ ++ sigset_t all_blocked; ++ sigfillset (&all_blocked); ++ sigset_t old_set; ++ xpthread_sigmask (SIG_SETMASK, &all_blocked, &old_set); ++ /* Create a detached thread. */ ++ pthread_t thr = xpthread_create ++ (NULL, delayed_exit_thread, (void *) (uintptr_t) seconds); ++ xpthread_detach (thr); ++ /* Restore the original signal mask. */ ++ xpthread_sigmask (SIG_SETMASK, &old_set, NULL); ++} +diff --git a/support/format_nss.h b/support/format_nss.h +new file mode 100644 +index 0000000000..fb4597c238 +--- /dev/null ++++ b/support/format_nss.h +@@ -0,0 +1,41 @@ ++/* String formatting functions for NSS- and DNS-related data. ++ 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 ++ . */ ++ ++#ifndef SUPPORT_FORMAT_NSS_H ++#define SUPPORT_FORMAT_NSS_H ++ ++#include ++#include ++ ++__BEGIN_DECLS ++ ++/* The following functions format their arguments as human-readable ++ strings (which can span multiple lines). The caller must free the ++ returned buffer. For NULL pointers or failure status arguments, ++ error variables such as h_errno and errno are included in the ++ result. */ ++char *support_format_address_family (int); ++char *support_format_addrinfo (struct addrinfo *, int ret); ++char *support_format_dns_packet (const unsigned char *buffer, size_t length); ++char *support_format_herrno (int); ++char *support_format_hostent (struct hostent *); ++char *support_format_netent (struct netent *); ++ ++__END_DECLS ++ ++#endif /* SUPPORT_FORMAT_NSS_H */ +diff --git a/support/ignore_stderr.c b/support/ignore_stderr.c +new file mode 100644 +index 0000000000..7b77a2cd56 +--- /dev/null ++++ b/support/ignore_stderr.c +@@ -0,0 +1,38 @@ ++/* Avoid all the buffer overflow messages on stderr. ++ Copyright (C) 2015-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 ++ ++void ++ignore_stderr (void) ++{ ++ int fd = open (_PATH_DEVNULL, O_WRONLY); ++ if (fd == -1) ++ close (STDERR_FILENO); ++ else ++ { ++ dup2 (fd, STDERR_FILENO); ++ close (fd); ++ } ++ setenv ("LIBC_FATAL_STDERR_", "1", 1); ++} +diff --git a/support/namespace.h b/support/namespace.h +new file mode 100644 +index 0000000000..e1ccaa1ef0 +--- /dev/null ++++ b/support/namespace.h +@@ -0,0 +1,65 @@ ++/* Entering namespaces for test case isolation. ++ 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 ++ . */ ++ ++#ifndef SUPPORT_NAMESPACE_H ++#define SUPPORT_NAMESPACE_H ++ ++#include ++#include ++ ++__BEGIN_DECLS ++ ++/* Attempts to become root (or acquire root-like privileges), possibly ++ with the help of user namespaces. Return true if (restricted) root ++ privileges could be attained in some way. Print diagnostics to ++ standard output. ++ ++ Note that this function generally has to be called before a process ++ becomes multi-threaded, otherwise it may fail with insufficient ++ privileges on systems which would support this operation for ++ 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. ++ If a network namespace could be created, but networking in it could ++ not be configured, terminate the process. It is recommended to ++ call support_become_root before this function so that the process ++ has sufficient privileges. */ ++bool support_enter_network_namespace (void); ++ ++/* Return true if support_enter_network_namespace managed to enter a ++ 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); ++ ++__END_DECLS ++ ++#endif +diff --git a/sysdeps/sparc/sparc64/fpu/s_fdimf.S b/support/oom_error.c +similarity index 69% +rename from sysdeps/sparc/sparc64/fpu/s_fdimf.S +rename to support/oom_error.c +index 356c23c4e3..7816978273 100644 +--- a/sysdeps/sparc/sparc64/fpu/s_fdimf.S ++++ b/support/oom_error.c +@@ -1,7 +1,6 @@ +-/* Compute positive difference, sparc 64-bit. +- Copyright (C) 2013-2016 Free Software Foundation, Inc. ++/* Reporting out-of-memory errors. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. +- Contributed by David S. Miller . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public +@@ -17,15 +16,14 @@ + License along with the GNU C Library; if not, see + . */ + +-#include ++#include + +-ENTRY(__fdimf) +- fcmps %f1, %f3 +- fbug 1f +- nop +- fzeros %f1 +- fnegs %f1, %f3 +-1: retl +- fsubs %f1, %f3, %f0 +-END(__fdimf) +-weak_alias (__fdimf, fdimf) ++#include ++#include ++ ++void ++oom_error (const char *function, size_t size) ++{ ++ printf ("%s: unable to allocate %zu bytes: %m\n", function, size); ++ exit (1); ++} +diff --git a/support/resolv_test.c b/support/resolv_test.c +new file mode 100644 +index 0000000000..050cd7154b +--- /dev/null ++++ b/support/resolv_test.c +@@ -0,0 +1,1202 @@ ++/* DNS test framework and libresolv redirection. ++ 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Response builder. */ ++ ++enum ++ { ++ max_response_length = 65536 ++ }; ++ ++/* List of pointers to be freed. The hash table implementation ++ (struct hsearch_data) does not provide a way to deallocate all ++ objects, so this approach is used to avoid memory leaks. */ ++struct to_be_freed ++{ ++ struct to_be_freed *next; ++ void *ptr; ++}; ++ ++struct resolv_response_builder ++{ ++ const unsigned char *query_buffer; ++ size_t query_length; ++ ++ size_t offset; /* Bytes written so far in buffer. */ ++ ns_sect section; /* Current section in the DNS packet. */ ++ unsigned int truncate_bytes; /* Bytes to remove at end of response. */ ++ bool drop; /* Discard generated response. */ ++ bool close; /* Close TCP client connection. */ ++ ++ /* Offset of the two-byte RDATA length field in the currently ++ written RDATA sub-structure. 0 if no RDATA is being written. */ ++ size_t current_rdata_offset; ++ ++ /* Hash table for locating targets for label compression. */ ++ struct hsearch_data compression_offsets; ++ /* List of pointers which need to be freed. Used for domain names ++ involved in label compression. */ ++ struct to_be_freed *to_be_freed; ++ ++ /* Must be last. Not zeroed for performance reasons. */ ++ unsigned char buffer[max_response_length]; ++}; ++ ++/* Response builder. */ ++ ++/* Add a pointer to the list of pointers to be freed when B is ++ deallocated. */ ++static void ++response_push_pointer_to_free (struct resolv_response_builder *b, void *ptr) ++{ ++ if (ptr == NULL) ++ return; ++ struct to_be_freed *e = xmalloc (sizeof (*e)); ++ *e = (struct to_be_freed) {b->to_be_freed, ptr}; ++ b->to_be_freed = e; ++} ++ ++void ++resolv_response_init (struct resolv_response_builder *b, ++ struct resolv_response_flags flags) ++{ ++ if (b->offset > 0) ++ FAIL_EXIT1 ("response_init: called at offset %zu", b->offset); ++ if (b->query_length < 12) ++ FAIL_EXIT1 ("response_init called for a query of size %zu", ++ b->query_length); ++ if (flags.rcode > 15) ++ FAIL_EXIT1 ("response_init: invalid RCODE %u", flags.rcode); ++ ++ /* Copy the transaction ID. */ ++ b->buffer[0] = b->query_buffer[0]; ++ b->buffer[1] = b->query_buffer[1]; ++ ++ /* Initialize the flags. */ ++ b->buffer[2] = 0x80; /* Mark as response. */ ++ b->buffer[2] |= b->query_buffer[2] & 0x01; /* Copy the RD bit. */ ++ if (flags.tc) ++ b->buffer[2] |= 0x02; ++ b->buffer[3] = 0x80 | flags.rcode; /* Always set RA. */ ++ ++ /* Fill in the initial section count values. */ ++ b->buffer[4] = flags.qdcount >> 8; ++ b->buffer[5] = flags.qdcount; ++ b->buffer[6] = flags.ancount >> 8; ++ b->buffer[7] = flags.ancount; ++ b->buffer[8] = flags.nscount >> 8; ++ b->buffer[9] = flags.nscount; ++ b->buffer[10] = flags.adcount >> 8; ++ b->buffer[11] = flags.adcount; ++ ++ b->offset = 12; ++} ++ ++void ++resolv_response_section (struct resolv_response_builder *b, ns_sect section) ++{ ++ if (b->offset == 0) ++ FAIL_EXIT1 ("resolv_response_section: response_init not called before"); ++ if (section < b->section) ++ FAIL_EXIT1 ("resolv_response_section: cannot go back to previous section"); ++ b->section = section; ++} ++ ++/* Add a single byte to B. */ ++static inline void ++response_add_byte (struct resolv_response_builder *b, unsigned char ch) ++{ ++ if (b->offset == max_response_length) ++ FAIL_EXIT1 ("DNS response exceeds 64 KiB limit"); ++ b->buffer[b->offset] = ch; ++ ++b->offset; ++} ++ ++/* Add a 16-bit word VAL to B, in big-endian format. */ ++static void ++response_add_16 (struct resolv_response_builder *b, uint16_t val) ++{ ++ response_add_byte (b, val >> 8); ++ response_add_byte (b, val); ++} ++ ++/* Increment the pers-section record counter in the packet header. */ ++static void ++response_count_increment (struct resolv_response_builder *b) ++{ ++ unsigned int offset = b->section; ++ offset = 4 + 2 * offset; ++ ++b->buffer[offset + 1]; ++ if (b->buffer[offset + 1] == 0) ++ { ++ /* Carry. */ ++ ++b->buffer[offset]; ++ if (b->buffer[offset] == 0) ++ /* Overflow. */ ++ FAIL_EXIT1 ("too many records in section"); ++ } ++} ++ ++void ++resolv_response_add_question (struct resolv_response_builder *b, ++ const char *name, uint16_t class, uint16_t type) ++{ ++ if (b->offset == 0) ++ FAIL_EXIT1 ("resolv_response_add_question: " ++ "resolv_response_init not called"); ++ if (b->section != ns_s_qd) ++ FAIL_EXIT1 ("resolv_response_add_question: " ++ "must be called in the question section"); ++ ++ resolv_response_add_name (b, name); ++ response_add_16 (b, type); ++ response_add_16 (b, class); ++ ++ response_count_increment (b); ++} ++ ++void ++resolv_response_add_name (struct resolv_response_builder *b, ++ const char *const origname) ++{ ++ /* Normalized name. */ ++ char *name; ++ /* Normalized name with case preserved. */ ++ char *name_case; ++ { ++ size_t namelen = strlen (origname); ++ /* Remove trailing dots. FIXME: Handle trailing quoted dots. */ ++ while (namelen > 0 && origname[namelen - 1] == '.') ++ --namelen; ++ name = xmalloc (namelen + 1); ++ name_case = xmalloc (namelen + 1); ++ /* Copy and convert to lowercase. FIXME: This needs to normalize ++ escaping as well. */ ++ for (size_t i = 0; i < namelen; ++i) ++ { ++ char ch = origname[i]; ++ name_case[i] = ch; ++ if ('A' <= ch && ch <= 'Z') ++ ch = ch - 'A' + 'a'; ++ name[i] = ch; ++ } ++ name[namelen] = 0; ++ name_case[namelen] = 0; ++ } ++ char *name_start = name; ++ char *name_case_start = name_case; ++ ++ bool compression = false; ++ while (*name) ++ { ++ /* Search for a previous name we can reference. */ ++ ENTRY new_entry = ++ { ++ .key = name, ++ .data = (void *) (uintptr_t) b->offset, ++ }; ++ ++ /* If the label can be a compression target because it is at a ++ reachable offset, add it to the hash table. */ ++ ACTION action; ++ if (b->offset < (1 << 12)) ++ action = ENTER; ++ else ++ action = FIND; ++ ++ /* Search for known compression offsets in the hash table. */ ++ ENTRY *e; ++ if (hsearch_r (new_entry, action, &e, &b->compression_offsets) == 0) ++ { ++ if (action == FIND && errno == ESRCH) ++ /* Fall through. */ ++ e = NULL; ++ else ++ FAIL_EXIT1 ("hsearch_r failure in name compression: %m"); ++ } ++ ++ /* The name is known. Reference the previous location. */ ++ if (e != NULL && e->data != new_entry.data) ++ { ++ size_t old_offset = (uintptr_t) e->data; ++ response_add_byte (b, 0xC0 | (old_offset >> 8)); ++ response_add_byte (b, old_offset); ++ compression = true; ++ break; ++ } ++ ++ /* The name does not exist yet. Write one label. First, add ++ room for the label length. */ ++ size_t buffer_label_offset = b->offset; ++ response_add_byte (b, 0); ++ ++ /* Copy the label. */ ++ while (true) ++ { ++ char ch = *name_case; ++ if (ch == '\0') ++ break; ++ ++name; ++ ++name_case; ++ if (ch == '.') ++ break; ++ /* FIXME: Handle escaping. */ ++ response_add_byte (b, ch); ++ } ++ ++ /* Patch in the label length. */ ++ size_t label_length = b->offset - buffer_label_offset - 1; ++ if (label_length == 0) ++ FAIL_EXIT1 ("empty label in name compression: %s", origname); ++ if (label_length > 63) ++ FAIL_EXIT1 ("label too long in name compression: %s", origname); ++ b->buffer[buffer_label_offset] = label_length; ++ ++ /* Continue with the tail of the name and the next label. */ ++ } ++ ++ if (compression) ++ { ++ /* If we found an immediate match for the name, we have not put ++ it into the hash table, and can free it immediately. */ ++ if (name == name_start) ++ free (name_start); ++ else ++ response_push_pointer_to_free (b, name_start); ++ } ++ else ++ { ++ /* Terminate the sequence of labels. With compression, this is ++ implicit in the compression reference. */ ++ response_add_byte (b, 0); ++ response_push_pointer_to_free (b, name_start); ++ } ++ ++ free (name_case_start); ++} ++ ++void ++resolv_response_open_record (struct resolv_response_builder *b, ++ const char *name, ++ uint16_t class, uint16_t type, uint32_t ttl) ++{ ++ if (b->section == ns_s_qd) ++ FAIL_EXIT1 ("resolv_response_open_record called in question section"); ++ if (b->current_rdata_offset != 0) ++ FAIL_EXIT1 ("resolv_response_open_record called with open record"); ++ ++ resolv_response_add_name (b, name); ++ response_add_16 (b, type); ++ response_add_16 (b, class); ++ response_add_16 (b, ttl >> 16); ++ response_add_16 (b, ttl); ++ ++ b->current_rdata_offset = b->offset; ++ /* Add room for the RDATA length. */ ++ response_add_16 (b, 0); ++} ++ ++ ++void ++resolv_response_close_record (struct resolv_response_builder *b) ++{ ++ size_t rdata_offset = b->current_rdata_offset; ++ if (rdata_offset == 0) ++ FAIL_EXIT1 ("response_close_record called without open record"); ++ size_t rdata_length = b->offset - rdata_offset - 2; ++ if (rdata_length > 65535) ++ FAIL_EXIT1 ("RDATA length %zu exceeds limit", rdata_length); ++ b->buffer[rdata_offset] = rdata_length >> 8; ++ b->buffer[rdata_offset + 1] = rdata_length; ++ response_count_increment (b); ++ b->current_rdata_offset = 0; ++} ++ ++void ++resolv_response_add_data (struct resolv_response_builder *b, ++ const void *data, size_t length) ++{ ++ size_t remaining = max_response_length - b->offset; ++ if (remaining < length) ++ FAIL_EXIT1 ("resolv_response_add_data: not enough room for %zu bytes", ++ length); ++ memcpy (b->buffer + b->offset, data, length); ++ b->offset += length; ++} ++ ++void ++resolv_response_drop (struct resolv_response_builder *b) ++{ ++ b->drop = true; ++} ++ ++void ++resolv_response_close (struct resolv_response_builder *b) ++{ ++ b->close = true; ++} ++ ++void ++resolv_response_truncate_data (struct resolv_response_builder *b, size_t count) ++{ ++ if (count > 65535) ++ FAIL_EXIT1 ("resolv_response_truncate_data: argument too large: %zu", ++ count); ++ b->truncate_bytes = count; ++} ++ ++ ++size_t ++resolv_response_length (const struct resolv_response_builder *b) ++{ ++ return b->offset; ++} ++ ++unsigned char * ++resolv_response_buffer (const struct resolv_response_builder *b) ++{ ++ unsigned char *result = xmalloc (b->offset); ++ memcpy (result, b->buffer, b->offset); ++ return result; ++} ++ ++static struct resolv_response_builder * ++response_builder_allocate ++ (const unsigned char *query_buffer, size_t query_length) ++{ ++ struct resolv_response_builder *b = xmalloc (sizeof (*b)); ++ memset (b, 0, offsetof (struct resolv_response_builder, buffer)); ++ b->query_buffer = query_buffer; ++ b->query_length = query_length; ++ TEST_VERIFY_EXIT (hcreate_r (10000, &b->compression_offsets) != 0); ++ return b; ++} ++ ++static void ++response_builder_free (struct resolv_response_builder *b) ++{ ++ struct to_be_freed *current = b->to_be_freed; ++ while (current != NULL) ++ { ++ struct to_be_freed *next = current->next; ++ free (current->ptr); ++ free (current); ++ current = next; ++ } ++ hdestroy_r (&b->compression_offsets); ++ free (b); ++} ++ ++/* DNS query processing. */ ++ ++/* Data extracted from the question section of a DNS packet. */ ++struct query_info ++{ ++ char qname[MAXDNAME]; ++ uint16_t qclass; ++ uint16_t qtype; ++ struct resolv_edns_info edns; ++}; ++ ++/* Update *INFO from the specified DNS packet. */ ++static void ++parse_query (struct query_info *info, ++ const unsigned char *buffer, size_t length) ++{ ++ HEADER hd; ++ _Static_assert (sizeof (hd) == 12, "DNS header size"); ++ if (length < sizeof (hd)) ++ FAIL_EXIT1 ("malformed DNS query: too short: %zu bytes", length); ++ 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"); ++ ++ /* Obtain QTYPE and QCLASS. */ ++ size_t remaining = length - (12 + ret); ++ struct ++ { ++ uint16_t qtype; ++ uint16_t qclass; ++ } qtype_qclass; ++ if (remaining < sizeof (qtype_qclass)) ++ FAIL_EXIT1 ("malformed DNS query: " ++ "query lacks QCLASS/QTYPE, QNAME: %s", info->qname); ++ 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); ++ } ++} ++ ++ ++/* Main testing framework. */ ++ ++/* Per-server information. One struct is allocated for each test ++ server. */ ++struct resolv_test_server ++{ ++ /* Local address of the server. UDP and TCP use the same port. */ ++ struct sockaddr_in address; ++ ++ /* File descriptor of the UDP server, or -1 if this server is ++ disabled. */ ++ int socket_udp; ++ ++ /* File descriptor of the TCP server, or -1 if this server is ++ disabled. */ ++ int socket_tcp; ++ ++ /* Counter of the number of responses processed so far. */ ++ size_t response_number; ++ ++ /* Thread handles for the server threads (if not disabled in the ++ configuration). */ ++ pthread_t thread_udp; ++ pthread_t thread_tcp; ++}; ++ ++/* Main struct for keeping track of libresolv redirection and ++ testing. */ ++struct resolv_test ++{ ++ /* After initialization, any access to the struct must be performed ++ while this lock is acquired. */ ++ pthread_mutex_t lock; ++ ++ /* Data for each test server. */ ++ struct resolv_test_server servers[resolv_max_test_servers]; ++ ++ /* Used if config.single_thread_udp is true. */ ++ pthread_t thread_udp_single; ++ ++ struct resolv_redirect_config config; ++ bool termination_requested; ++}; ++ ++/* Function implementing a server thread. */ ++typedef void (*thread_callback) (struct resolv_test *, int server_index); ++ ++/* Storage for thread-specific data, for passing to the ++ thread_callback function. */ ++struct thread_closure ++{ ++ struct resolv_test *obj; /* Current test object. */ ++ thread_callback callback; /* Function to call. */ ++ int server_index; /* Index of the implemented server. */ ++}; ++ ++/* Wrap response_callback as a function which can be passed to ++ pthread_create. */ ++static void * ++thread_callback_wrapper (void *arg) ++{ ++ struct thread_closure *closure = arg; ++ closure->callback (closure->obj, closure->server_index); ++ free (closure); ++ return NULL; ++} ++ ++/* Start a server thread for the specified SERVER_INDEX, implemented ++ by CALLBACK. */ ++static pthread_t ++start_server_thread (struct resolv_test *obj, int server_index, ++ thread_callback callback) ++{ ++ struct thread_closure *closure = xmalloc (sizeof (*closure)); ++ *closure = (struct thread_closure) ++ { ++ .obj = obj, ++ .callback = callback, ++ .server_index = server_index, ++ }; ++ return xpthread_create (NULL, thread_callback_wrapper, closure); ++} ++ ++/* Process one UDP query. Return false if a termination requested has ++ been detected. */ ++static bool ++server_thread_udp_process_one (struct resolv_test *obj, int server_index) ++{ ++ unsigned char query[512]; ++ struct sockaddr_storage peer; ++ socklen_t peerlen = sizeof (peer); ++ size_t length = xrecvfrom (obj->servers[server_index].socket_udp, ++ query, sizeof (query), 0, ++ (struct sockaddr *) &peer, &peerlen); ++ /* Check for termination. */ ++ { ++ bool termination_requested; ++ xpthread_mutex_lock (&obj->lock); ++ termination_requested = obj->termination_requested; ++ xpthread_mutex_unlock (&obj->lock); ++ if (termination_requested) ++ return false; ++ } ++ ++ ++ struct query_info qinfo; ++ parse_query (&qinfo, query, length); ++ if (test_verbose > 0) ++ { ++ if (test_verbose > 1) ++ printf ("info: UDP server %d: incoming query:" ++ " %zd bytes, %s/%u/%u, tnxid=0x%02x%02x\n", ++ server_index, length, qinfo.qname, qinfo.qclass, qinfo.qtype, ++ query[0], query[1]); ++ else ++ printf ("info: UDP server %d: incoming query:" ++ " %zd bytes, %s/%u/%u\n", ++ server_index, length, qinfo.qname, qinfo.qclass, qinfo.qtype); ++ } ++ ++ struct resolv_response_context ctx = ++ { ++ .query_buffer = query, ++ .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 ++ (&ctx, b, qinfo.qname, qinfo.qclass, qinfo.qtype); ++ ++ if (b->drop) ++ { ++ if (test_verbose) ++ printf ("info: UDP server %d: dropping response to %s/%u/%u\n", ++ server_index, qinfo.qname, qinfo.qclass, qinfo.qtype); ++ } ++ else ++ { ++ if (test_verbose) ++ { ++ if (b->offset >= 12) ++ printf ("info: UDP server %d: sending response:" ++ " %zu bytes, RCODE %d (for %s/%u/%u)\n", ++ server_index, b->offset, b->buffer[3] & 0x0f, ++ qinfo.qname, qinfo.qclass, qinfo.qtype); ++ else ++ printf ("info: UDP server %d: sending response: %zu bytes" ++ " (for %s/%u/%u)\n", ++ server_index, b->offset, ++ qinfo.qname, qinfo.qclass, qinfo.qtype); ++ if (b->truncate_bytes > 0) ++ printf ("info: truncated by %u bytes\n", b->truncate_bytes); ++ } ++ size_t to_send = b->offset; ++ if (to_send < b->truncate_bytes) ++ to_send = 0; ++ else ++ to_send -= b->truncate_bytes; ++ ++ /* Ignore most errors here because the other end may have closed ++ the socket. */ ++ if (sendto (obj->servers[server_index].socket_udp, ++ b->buffer, to_send, 0, ++ (struct sockaddr *) &peer, peerlen) < 0) ++ TEST_VERIFY_EXIT (errno != EBADF); ++ } ++ response_builder_free (b); ++ return true; ++} ++ ++/* UDP thread_callback function. Variant for one thread per ++ server. */ ++static void ++server_thread_udp (struct resolv_test *obj, int server_index) ++{ ++ while (server_thread_udp_process_one (obj, server_index)) ++ ; ++} ++ ++/* Single-threaded UDP processing function, for the single_thread_udp ++ case. */ ++static void * ++server_thread_udp_single (void *closure) ++{ ++ struct resolv_test *obj = closure; ++ ++ struct pollfd fds[resolv_max_test_servers]; ++ for (int server_index = 0; server_index < resolv_max_test_servers; ++ ++server_index) ++ if (obj->config.servers[server_index].disable_udp) ++ fds[server_index] = (struct pollfd) {.fd = -1}; ++ else ++ { ++ fds[server_index] = (struct pollfd) ++ { ++ .fd = obj->servers[server_index].socket_udp, ++ .events = POLLIN ++ }; ++ ++ /* Make the socket non-blocking. */ ++ int flags = fcntl (obj->servers[server_index].socket_udp, F_GETFL, 0); ++ if (flags < 0) ++ FAIL_EXIT1 ("fcntl (F_GETFL): %m"); ++ flags |= O_NONBLOCK; ++ if (fcntl (obj->servers[server_index].socket_udp, F_SETFL, flags) < 0) ++ FAIL_EXIT1 ("fcntl (F_SETFL): %m"); ++ } ++ ++ while (true) ++ { ++ xpoll (fds, resolv_max_test_servers, -1); ++ for (int server_index = 0; server_index < resolv_max_test_servers; ++ ++server_index) ++ if (fds[server_index].revents != 0) ++ { ++ if (!server_thread_udp_process_one (obj, server_index)) ++ goto out; ++ fds[server_index].revents = 0; ++ } ++ } ++ ++ out: ++ return NULL; ++} ++ ++/* Start the single UDP handler thread (for the single_thread_udp ++ case). */ ++static void ++start_server_thread_udp_single (struct resolv_test *obj) ++{ ++ obj->thread_udp_single ++ = xpthread_create (NULL, server_thread_udp_single, obj); ++} ++ ++/* Data describing a TCP client connect. */ ++struct tcp_thread_closure ++{ ++ struct resolv_test *obj; ++ int server_index; ++ int client_socket; ++}; ++ ++/* Read a complete DNS query packet. If EOF_OK, an immediate ++ end-of-file condition is acceptable. */ ++static bool ++read_fully (int fd, void *buf, size_t len, bool eof_ok) ++{ ++ const void *const end = buf + len; ++ while (buf < end) ++ { ++ ssize_t ret = read (fd, buf, end - buf); ++ if (ret == 0) ++ { ++ if (!eof_ok) ++ { ++ support_record_failure (); ++ printf ("error: unexpected EOF on TCP connection\n"); ++ } ++ return false; ++ } ++ else if (ret < 0) ++ { ++ if (!eof_ok || errno != ECONNRESET) ++ { ++ support_record_failure (); ++ printf ("error: TCP read: %m\n"); ++ } ++ return false; ++ } ++ buf += ret; ++ eof_ok = false; ++ } ++ return true; ++} ++ ++/* Write an array of iovecs. Terminate the process on failure. */ ++static void ++writev_fully (int fd, struct iovec *buffers, size_t count) ++{ ++ while (count > 0) ++ { ++ /* Skip zero-length write requests. */ ++ if (buffers->iov_len == 0) ++ { ++ ++buffers; ++ --count; ++ continue; ++ } ++ /* Try to rewrite the remaing buffers. */ ++ ssize_t ret = writev (fd, buffers, count); ++ if (ret < 0) ++ FAIL_EXIT1 ("writev: %m"); ++ if (ret == 0) ++ FAIL_EXIT1 ("writev: invalid return value zero"); ++ /* Find the buffers that were successfully written. */ ++ while (ret > 0) ++ { ++ if (count == 0) ++ FAIL_EXIT1 ("internal writev consistency failure"); ++ /* Current buffer was partially written. */ ++ if (buffers->iov_len > (size_t) ret) ++ { ++ buffers->iov_base += ret; ++ buffers->iov_len -= ret; ++ ret = 0; ++ } ++ else ++ { ++ ret -= buffers->iov_len; ++ buffers->iov_len = 0; ++ ++buffers; ++ --count; ++ } ++ } ++ } ++} ++ ++/* Thread callback for handling a single established TCP connection to ++ a client. */ ++static void * ++server_thread_tcp_client (void *arg) ++{ ++ struct tcp_thread_closure *closure = arg; ++ ++ while (true) ++ { ++ /* Read packet length. */ ++ uint16_t query_length; ++ if (!read_fully (closure->client_socket, ++ &query_length, sizeof (query_length), true)) ++ break; ++ query_length = ntohs (query_length); ++ ++ /* Read the packet. */ ++ unsigned char *query_buffer = xmalloc (query_length); ++ read_fully (closure->client_socket, query_buffer, query_length, false); ++ ++ struct query_info qinfo; ++ parse_query (&qinfo, query_buffer, query_length); ++ if (test_verbose > 0) ++ { ++ if (test_verbose > 1) ++ printf ("info: UDP server %d: incoming query:" ++ " %d bytes, %s/%u/%u, tnxid=0x%02x%02x\n", ++ closure->server_index, query_length, ++ qinfo.qname, qinfo.qclass, qinfo.qtype, ++ query_buffer[0], query_buffer[1]); ++ else ++ printf ("info: TCP server %d: incoming query:" ++ " %u bytes, %s/%u/%u\n", ++ closure->server_index, query_length, ++ qinfo.qname, qinfo.qclass, qinfo.qtype); ++ } ++ ++ struct resolv_response_context ctx = ++ { ++ .query_buffer = query_buffer, ++ .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); ++ closure->obj->config.response_callback ++ (&ctx, b, qinfo.qname, qinfo.qclass, qinfo.qtype); ++ ++ if (b->drop) ++ { ++ if (test_verbose) ++ printf ("info: TCP server %d: dropping response to %s/%u/%u\n", ++ closure->server_index, ++ qinfo.qname, qinfo.qclass, qinfo.qtype); ++ } ++ else ++ { ++ if (test_verbose) ++ printf ("info: TCP server %d: sending response: %zu bytes" ++ " (for %s/%u/%u)\n", ++ closure->server_index, b->offset, ++ qinfo.qname, qinfo.qclass, qinfo.qtype); ++ uint16_t length = htons (b->offset); ++ size_t to_send = b->offset; ++ if (to_send < b->truncate_bytes) ++ to_send = 0; ++ else ++ to_send -= b->truncate_bytes; ++ struct iovec buffers[2] = ++ { ++ {&length, sizeof (length)}, ++ {b->buffer, to_send} ++ }; ++ writev_fully (closure->client_socket, buffers, 2); ++ } ++ bool close_flag = b->close; ++ response_builder_free (b); ++ free (query_buffer); ++ if (close_flag) ++ break; ++ } ++ ++ xclose (closure->client_socket); ++ free (closure); ++ return NULL; ++} ++ ++/* thread_callback for the TCP case. Accept connections and create a ++ new thread for each client. */ ++static void ++server_thread_tcp (struct resolv_test *obj, int server_index) ++{ ++ while (true) ++ { ++ /* Get the client conenction. */ ++ int client_socket = xaccept ++ (obj->servers[server_index].socket_tcp, NULL, NULL); ++ ++ /* Check for termination. */ ++ xpthread_mutex_lock (&obj->lock); ++ if (obj->termination_requested) ++ { ++ xpthread_mutex_unlock (&obj->lock); ++ xclose (client_socket); ++ break; ++ } ++ xpthread_mutex_unlock (&obj->lock); ++ ++ /* Spawn a new thread for handling this connection. */ ++ struct tcp_thread_closure *closure = xmalloc (sizeof (*closure)); ++ *closure = (struct tcp_thread_closure) ++ { ++ .obj = obj, ++ .server_index = server_index, ++ .client_socket = client_socket, ++ }; ++ ++ pthread_t thr ++ = xpthread_create (NULL, server_thread_tcp_client, closure); ++ /* TODO: We should keep track of this thread so that we can ++ block in resolv_test_end until it has exited. */ ++ xpthread_detach (thr); ++ } ++} ++ ++/* Create UDP and TCP server sockets. */ ++static void ++make_server_sockets (struct resolv_test_server *server) ++{ ++ while (true) ++ { ++ server->socket_udp = xsocket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); ++ server->socket_tcp = xsocket (AF_INET, SOCK_STREAM, IPPROTO_TCP); ++ ++ /* Pick the address for the UDP socket. */ ++ server->address = (struct sockaddr_in) ++ { ++ .sin_family = AF_INET, ++ .sin_addr = {.s_addr = htonl (INADDR_LOOPBACK)} ++ }; ++ xbind (server->socket_udp, ++ (struct sockaddr *)&server->address, sizeof (server->address)); ++ ++ /* Retrieve the address. */ ++ socklen_t addrlen = sizeof (server->address); ++ xgetsockname (server->socket_udp, ++ (struct sockaddr *)&server->address, &addrlen); ++ ++ /* Bind the TCP socket to the same address. */ ++ { ++ int on = 1; ++ xsetsockopt (server->socket_tcp, SOL_SOCKET, SO_REUSEADDR, ++ &on, sizeof (on)); ++ } ++ if (bind (server->socket_tcp, ++ (struct sockaddr *)&server->address, ++ sizeof (server->address)) != 0) ++ { ++ /* Port collision. The UDP bind succeeded, but the TCP BIND ++ failed. We assume here that the kernel will pick the ++ next local UDP address randomly. */ ++ if (errno == EADDRINUSE) ++ { ++ xclose (server->socket_udp); ++ xclose (server->socket_tcp); ++ continue; ++ } ++ FAIL_EXIT1 ("TCP bind: %m"); ++ } ++ xlisten (server->socket_tcp, 5); ++ break; ++ } ++} ++ ++/* One-time initialization of NSS. */ ++static void ++resolv_redirect_once (void) ++{ ++ /* Only use nss_dns. */ ++ __nss_configure_lookup ("hosts", "dns"); ++ __nss_configure_lookup ("networks", "dns"); ++ /* Enter a network namespace for isolation and firewall state ++ cleanup. The tests will still work if these steps fail, but they ++ may be less reliable. */ ++ support_become_root (); ++ support_enter_network_namespace (); ++} ++pthread_once_t resolv_redirect_once_var = PTHREAD_ONCE_INIT; ++ ++void ++resolv_test_init (void) ++{ ++ /* Perform one-time initialization of NSS. */ ++ xpthread_once (&resolv_redirect_once_var, resolv_redirect_once); ++} ++ ++/* Copy the search path from CONFIG.search to the _res object. */ ++static void ++set_search_path (struct resolv_redirect_config config) ++{ ++ memset (_res.defdname, 0, sizeof (_res.defdname)); ++ memset (_res.dnsrch, 0, sizeof (_res.dnsrch)); ++ ++ char *current = _res.defdname; ++ char *end = current + sizeof (_res.defdname); ++ ++ for (unsigned int i = 0; ++ i < sizeof (config.search) / sizeof (config.search[0]); ++i) ++ { ++ if (config.search[i] == NULL) ++ continue; ++ ++ size_t length = strlen (config.search[i]) + 1; ++ size_t remaining = end - current; ++ TEST_VERIFY_EXIT (length <= remaining); ++ memcpy (current, config.search[i], length); ++ _res.dnsrch[i] = current; ++ current += length; ++ } ++} ++ ++struct resolv_test * ++resolv_test_start (struct resolv_redirect_config config) ++{ ++ /* Apply configuration defaults. */ ++ if (config.nscount == 0) ++ config.nscount = resolv_max_test_servers; ++ ++ struct resolv_test *obj = xmalloc (sizeof (*obj)); ++ *obj = (struct resolv_test) { ++ .config = config, ++ .lock = PTHREAD_MUTEX_INITIALIZER, ++ }; ++ ++ 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); ++ ++ /* Start server threads. Disable the server ports, as ++ requested. */ ++ for (int server_index = 0; server_index < config.nscount; ++server_index) ++ { ++ struct resolv_test_server *server = obj->servers + server_index; ++ if (config.servers[server_index].disable_udp) ++ { ++ xclose (server->socket_udp); ++ server->socket_udp = -1; ++ } ++ else if (!config.single_thread_udp) ++ server->thread_udp = start_server_thread (obj, server_index, ++ server_thread_udp); ++ if (config.servers[server_index].disable_tcp) ++ { ++ xclose (server->socket_tcp); ++ server->socket_tcp = -1; ++ } ++ else ++ server->thread_tcp = start_server_thread (obj, server_index, ++ server_thread_tcp); ++ } ++ if (config.single_thread_udp) ++ start_server_thread_udp_single (obj); ++ ++ int timeout = 1; ++ ++ /* Initialize libresolv. */ ++ TEST_VERIFY_EXIT (res_init () == 0); ++ ++ /* Disable IPv6 name server addresses. The code below only ++ overrides the IPv4 addresses. */ ++ __res_iclose (&_res, true); ++ _res._u._ext.nscount = 0; ++ ++ /* Redirect queries to the server socket. */ ++ if (test_verbose) ++ { ++ printf ("info: old timeout value: %d\n", _res.retrans); ++ printf ("info: old retry attempt value: %d\n", _res.retry); ++ printf ("info: old _res.options: 0x%lx\n", _res.options); ++ printf ("info: old _res.nscount value: %d\n", _res.nscount); ++ printf ("info: old _res.ndots value: %d\n", _res.ndots); ++ } ++ _res.retrans = timeout; ++ _res.retry = 4; ++ _res.nscount = config.nscount; ++ _res.options = RES_INIT | RES_RECURSE | RES_DEFNAMES | RES_DNSRCH; ++ _res.ndots = 1; ++ if (test_verbose) ++ { ++ printf ("info: new timeout value: %d\n", _res.retrans); ++ printf ("info: new retry attempt value: %d\n", _res.retry); ++ printf ("info: new _res.options: 0x%lx\n", _res.options); ++ printf ("info: new _res.nscount value: %d\n", _res.nscount); ++ printf ("info: new _res.ndots value: %d\n", _res.ndots); ++ } ++ for (int server_index = 0; server_index < config.nscount; ++server_index) ++ { ++ _res.nsaddr_list[server_index] = obj->servers[server_index].address; ++ if (test_verbose) ++ { ++ char buf[256]; ++ TEST_VERIFY_EXIT ++ (inet_ntop (AF_INET, &obj->servers[server_index].address.sin_addr, ++ buf, sizeof (buf)) != NULL); ++ printf ("info: server %d: %s/%u\n", ++ server_index, buf, ++ htons (obj->servers[server_index].address.sin_port)); ++ } ++ } ++ ++ set_search_path (config); ++ ++ return obj; ++} ++ ++void ++resolv_test_end (struct resolv_test *obj) ++{ ++ res_close (); ++ ++ xpthread_mutex_lock (&obj->lock); ++ obj->termination_requested = true; ++ xpthread_mutex_unlock (&obj->lock); ++ ++ /* Send trigger packets to unblock the server threads. */ ++ for (int server_index = 0; server_index < obj->config.nscount; ++ ++server_index) ++ { ++ if (!obj->config.servers[server_index].disable_udp) ++ { ++ int sock = xsocket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); ++ xsendto (sock, "", 1, 0, ++ (struct sockaddr *) &obj->servers[server_index].address, ++ sizeof (obj->servers[server_index].address)); ++ xclose (sock); ++ } ++ if (!obj->config.servers[server_index].disable_tcp) ++ { ++ int sock = xsocket (AF_INET, SOCK_STREAM, IPPROTO_TCP); ++ xconnect (sock, ++ (struct sockaddr *) &obj->servers[server_index].address, ++ sizeof (obj->servers[server_index].address)); ++ xclose (sock); ++ } ++ } ++ ++ if (obj->config.single_thread_udp) ++ xpthread_join (obj->thread_udp_single); ++ ++ /* Wait for the server threads to terminate. */ ++ for (int server_index = 0; server_index < obj->config.nscount; ++ ++server_index) ++ { ++ if (!obj->config.servers[server_index].disable_udp) ++ { ++ if (!obj->config.single_thread_udp) ++ xpthread_join (obj->servers[server_index].thread_udp); ++ xclose (obj->servers[server_index].socket_udp); ++ } ++ if (!obj->config.servers[server_index].disable_tcp) ++ { ++ xpthread_join (obj->servers[server_index].thread_tcp); ++ xclose (obj->servers[server_index].socket_tcp); ++ } ++ } ++ ++ free (obj); ++} +diff --git a/support/resolv_test.h b/support/resolv_test.h +new file mode 100644 +index 0000000000..6498751569 +--- /dev/null ++++ b/support/resolv_test.h +@@ -0,0 +1,180 @@ ++/* DNS test framework and libresolv redirection. ++ 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 ++ . */ ++ ++#ifndef SUPPORT_RESOLV_TEST_H ++#define SUPPORT_RESOLV_TEST_H ++ ++#include ++#include ++#include ++ ++__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 ++{ ++ const unsigned char *query_buffer; ++ 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 ++ response callback function. */ ++struct resolv_response_builder; ++ ++/* This opaque struct collects information about the resolver testing ++ currently in progress. */ ++struct resolv_test; ++ ++enum ++ { ++ /* Maximum number of test servers supported by the framework. */ ++ resolv_max_test_servers = 3, ++ }; ++ ++/* Configuration settings specific to individual test servers. */ ++struct resolv_redirect_server_config ++{ ++ bool disable_tcp; /* If true, no TCP server is listening. */ ++ bool disable_udp; /* If true, no UDP server is listening. */ ++}; ++ ++/* Instructions for setting up the libresolv redirection. */ ++struct resolv_redirect_config ++{ ++ /* The response_callback function is called for every incoming DNS ++ packet, over UDP or TCP. It must be specified, the other ++ configuration settings are optional. */ ++ void (*response_callback) (const struct resolv_response_context *, ++ struct resolv_response_builder *, ++ const char *qname, ++ uint16_t qclass, uint16_t qtype); ++ ++ /* Per-server configuration. */ ++ struct resolv_redirect_server_config servers[resolv_max_test_servers]; ++ ++ /* Search path entries. The first entry serves as the default ++ domain name as well. */ ++ const char *search[7]; ++ ++ /* Number of servers to activate in resolv. 0 means the default, ++ resolv_max_test_servers. */ ++ int nscount; ++ ++ /* If true, use a single thread to process all UDP queries. This ++ may results in more predictable ordering of queries and ++ responses. */ ++ bool single_thread_udp; ++}; ++ ++/* Configure NSS to use, nss_dns only for aplicable databases, and try ++ to put the process into a network namespace for better isolation. ++ This may have to be called before resolv_test_start, before the ++ process creates any threads. Otherwise, initialization is ++ performed by resolv_test_start implicitly. */ ++void resolv_test_init (void); ++ ++/* Initiate resolver testing. This updates the _res variable as ++ needed. As a side effect, NSS is reconfigured to use nss_dns only ++ for aplicable databases, and the process may enter a network ++ namespace for better isolation. */ ++struct resolv_test *resolv_test_start (struct resolv_redirect_config); ++ ++/* Call this function at the end of resolver testing, to free ++ resources and report pending errors (if any). */ ++void resolv_test_end (struct resolv_test *); ++ ++/* The remaining facilities in this file are used for constructing ++ response packets from the response_callback function. */ ++ ++/* Special settings for constructing responses from the callback. */ ++struct resolv_response_flags ++{ ++ /* 4-bit response code to incorporate into the response. */ ++ unsigned char rcode; ++ ++ /* If true, the TC (truncation) flag will be set. */ ++ bool tc; ++ ++ /* Initial section count values. Can be used to artificially ++ increase the counts, for malformed packet testing.*/ ++ unsigned short qdcount; ++ unsigned short ancount; ++ unsigned short nscount; ++ unsigned short adcount; ++}; ++ ++/* Begin a new response with the requested flags. Must be called ++ first. */ ++void resolv_response_init (struct resolv_response_builder *, ++ struct resolv_response_flags); ++ ++/* Switches to the section in the response packet. Only forward ++ movement is supported. */ ++void resolv_response_section (struct resolv_response_builder *, ns_sect); ++ ++/* Add a question record to the question section. */ ++void resolv_response_add_question (struct resolv_response_builder *, ++ const char *name, uint16_t class, ++ uint16_t type); ++/* Starts a new resource record with the specified owner name, class, ++ type, and TTL. Data is supplied with resolv_response_add_data or ++ resolv_response_add_name. */ ++void resolv_response_open_record (struct resolv_response_builder *, ++ const char *name, uint16_t class, ++ uint16_t type, uint32_t ttl); ++ ++/* Add unstructed bytes to the RDATA part of a resource record. */ ++void resolv_response_add_data (struct resolv_response_builder *, ++ const void *, size_t); ++ ++/* Add a compressed domain name to the RDATA part of a resource ++ record. */ ++void resolv_response_add_name (struct resolv_response_builder *, ++ const char *name); ++ ++/* Mark the end of the constructed record. Must be called last. */ ++void resolv_response_close_record (struct resolv_response_builder *); ++ ++/* Drop this query packet (that is, do not send a response, not even ++ an empty packet). */ ++void resolv_response_drop (struct resolv_response_builder *); ++ ++/* In TCP mode, close the connection after this packet (if a response ++ is sent). */ ++void resolv_response_close (struct resolv_response_builder *); ++ ++/* The size of the response packet built so far. */ ++size_t resolv_response_length (const struct resolv_response_builder *); ++ ++__END_DECLS ++ ++#endif /* SUPPORT_RESOLV_TEST_H */ +diff --git a/support/run_diff.h b/support/run_diff.h +new file mode 100644 +index 0000000000..f65b5dd22c +--- /dev/null ++++ b/support/run_diff.h +@@ -0,0 +1,31 @@ ++/* Invoke the system diff tool to compare two strings. ++ 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 ++ . */ ++ ++#ifndef SUPPORT_RUN_DIFF_H ++#define SUPPORT_RUN_DIFF_H ++ ++/* Compare the two NUL-terminated strings LEFT and RIGHT using the ++ diff tool. Label the sides of the diff with LEFT_LABEL and ++ RIGHT_LABEL, respectively. ++ ++ This function assumes that LEFT and RIGHT are different ++ strings. */ ++void support_run_diff (const char *left_label, const char *left, ++ const char *right_label, const char *right); ++ ++#endif /* SUPPORT_RUN_DIFF_H */ +diff --git a/support/set_fortify_handler.c b/support/set_fortify_handler.c +new file mode 100644 +index 0000000000..f434a8082a +--- /dev/null ++++ b/support/set_fortify_handler.c +@@ -0,0 +1,34 @@ ++/* Set signal handler for use in fortify tests. ++ 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 ++ ++void ++set_fortify_handler (void (*handler) (int sig)) ++{ ++ struct sigaction sa; ++ ++ sa.sa_handler = handler; ++ sa.sa_flags = 0; ++ sigemptyset (&sa.sa_mask); ++ ++ sigaction (SIGABRT, &sa, NULL); ++ ignore_stderr (); ++} +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 +new file mode 100644 +index 0000000000..4b5f04c2cc +--- /dev/null ++++ b/support/support.h +@@ -0,0 +1,74 @@ ++/* Common extra functions. ++ 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 ++ . */ ++ ++/* This header file should only contain definitions compatible with ++ C90. (Using __attribute__ is fine because provides a ++ fallback.) */ ++ ++#ifndef SUPPORT_H ++#define SUPPORT_H ++ ++#include ++#include ++ ++__BEGIN_DECLS ++ ++/* Write a message to standard output. Can be used in signal ++ handlers. */ ++void write_message (const char *message) __attribute__ ((nonnull (1))); ++ ++/* Avoid all the buffer overflow messages on stderr. */ ++void ignore_stderr (void); ++ ++/* Set fortification error handler. Used when tests want to verify that bad ++ code is caught by the library. */ ++void set_fortify_handler (void (*handler) (int sig)); ++ ++/* Report an out-of-memory error for the allocation of SIZE bytes in ++ FUNCTION, terminating the process. */ ++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. */ ++ ++void *xmalloc (size_t) __attribute__ ((malloc)); ++void *xcalloc (size_t n, size_t s) __attribute__ ((malloc)); ++void *xrealloc (void *p, size_t n); ++char *xasprintf (const char *format, ...) ++ __attribute__ ((format (printf, 1, 2), malloc)); ++char *xstrdup (const char *); ++ ++__END_DECLS ++ ++#endif /* SUPPORT_H */ +diff --git a/sysdeps/sparc/sparc32/sparcv9/fpu/s_fdim.S b/support/support_become_root.c +similarity index 57% +rename from sysdeps/sparc/sparc32/sparcv9/fpu/s_fdim.S +rename to support/support_become_root.c +index 37f7f44dfa..3fa0bd4ac0 100644 +--- a/sysdeps/sparc/sparc32/sparcv9/fpu/s_fdim.S ++++ b/support/support_become_root.c +@@ -1,7 +1,6 @@ +-/* Compute positive difference, sparc 32-bit+v9. +- Copyright (C) 2013-2016 Free Software Foundation, Inc. ++/* Acquire root privileges. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. +- Contributed by David S. Miller . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public +@@ -17,24 +16,25 @@ + License along with the GNU C Library; if not, see + . */ + +-#include +-#include ++#include + +-ENTRY(__fdim) +- std %o0, [%sp + 72] +- std %o2, [%sp + 80] +- ldd [%sp + 72], %f0 +- ldd [%sp + 80], %f2 +- fcmpd %f0, %f2 +- fbug 1f +- nop +- fzero %f0 +- fnegd %f0, %f2 +-1: retl +- fsubd %f0, %f2, %f0 +-END(__fdim) +-weak_alias (__fdim, fdim) ++#include ++#include ++#include + +-#if LONG_DOUBLE_COMPAT(libm, GLIBC_2_1) +-compat_symbol (libm, __fdim, fdiml, GLIBC_2_1); ++bool ++support_become_root (void) ++{ ++#ifdef CLONE_NEWUSER ++ if (unshare (CLONE_NEWUSER | CLONE_NEWNS) == 0) ++ /* Even if we do not have UID zero, we have extended privileges at ++ this point. */ ++ return true; + #endif ++ if (setuid (0) != 0) ++ { ++ printf ("warning: could not become root outside namespace (%m)\n"); ++ return false; ++ } ++ return true; ++} +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..708c89f331 +--- /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", 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_enter_network_namespace.c b/support/support_enter_network_namespace.c +new file mode 100644 +index 0000000000..28b0ee29cf +--- /dev/null ++++ b/support/support_enter_network_namespace.c +@@ -0,0 +1,75 @@ ++/* Enter a network namespace. ++ 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 ++ ++static bool in_uts_namespace; ++ ++bool ++support_enter_network_namespace (void) ++{ ++#ifdef CLONE_NEWUTS ++ if (unshare (CLONE_NEWUTS) == 0) ++ in_uts_namespace = true; ++ else ++ printf ("warning: unshare (CLONE_NEWUTS) failed: %m\n"); ++#endif ++ ++#ifdef CLONE_NEWNET ++ if (unshare (CLONE_NEWNET) == 0) ++ { ++ /* Bring up the loopback interface. */ ++ int fd = xsocket (AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0); ++ struct ifreq req; ++ strcpy (req.ifr_name, "lo"); ++ TEST_VERIFY_EXIT (ioctl (fd, SIOCGIFFLAGS, &req) == 0); ++ bool already_up = req.ifr_flags & IFF_UP; ++ if (already_up) ++ /* This means that we likely have not achieved isolation from ++ the parent namespace. */ ++ printf ("warning: loopback interface already exists" ++ " in new network namespace\n"); ++ else ++ { ++ req.ifr_flags |= IFF_UP | IFF_RUNNING; ++ TEST_VERIFY_EXIT (ioctl (fd, SIOCSIFFLAGS, &req) == 0); ++ } ++ xclose (fd); ++ ++ return !already_up; ++ } ++#endif ++ printf ("warning: could not enter network namespace\n"); ++ return false; ++} ++ ++bool ++support_in_uts_namespace (void) ++{ ++ return in_uts_namespace; ++} +diff --git a/sysdeps/sparc/sparc32/sparcv9/fpu/s_fdimf.S b/support/support_format_address_family.c +similarity index 63% +rename from sysdeps/sparc/sparc32/sparcv9/fpu/s_fdimf.S +rename to support/support_format_address_family.c +index 9e0e3f21be..5d42c42a45 100644 +--- a/sysdeps/sparc/sparc32/sparcv9/fpu/s_fdimf.S ++++ b/support/support_format_address_family.c +@@ -1,7 +1,6 @@ +-/* Compute positive difference, sparc 32-bit+v9. +- Copyright (C) 2013-2016 Free Software Foundation, Inc. ++/* Convert an address family to a string. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. +- Contributed by David S. Miller . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public +@@ -17,19 +16,20 @@ + License along with the GNU C Library; if not, see + . */ + +-#include ++#include + +-ENTRY(__fdimf) +- st %o0, [%sp + 72] +- st %o1, [%sp + 76] +- ld [%sp + 72], %f0 +- ld [%sp + 76], %f1 +- fcmps %f0, %f1 +- fbug 1f +- nop +- fzeros %f0 +- fnegs %f0, %f1 +-1: retl +- fsubs %f0, %f1, %f0 +-END(__fdimf) +-weak_alias (__fdimf, fdimf) ++#include ++ ++char * ++support_format_address_family (int family) ++{ ++ switch (family) ++ { ++ case AF_INET: ++ return xstrdup ("INET"); ++ case AF_INET6: ++ return xstrdup ("INET6"); ++ default: ++ return xasprintf ("", family); ++ } ++} +diff --git a/support/support_format_addrinfo.c b/support/support_format_addrinfo.c +new file mode 100644 +index 0000000000..eedb030591 +--- /dev/null ++++ b/support/support_format_addrinfo.c +@@ -0,0 +1,239 @@ ++/* Convert struct addrinfo values to a string. ++ 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 size_t ++socket_address_length (int family) ++{ ++ switch (family) ++ { ++ case AF_INET: ++ return sizeof (struct sockaddr_in); ++ case AF_INET6: ++ return sizeof (struct sockaddr_in6); ++ default: ++ return -1; ++ } ++} ++ ++static void ++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); ++ *flags_printed |= flag; ++} ++ ++static void ++format_ai_flags (FILE *out, struct addrinfo *ai) ++{ ++ if (ai == NULL) ++ return; ++ ++ if (ai->ai_flags != 0) ++ { ++ fprintf (out, "flags:"); ++ int flags_printed = 0; ++#define FLAG(flag) format_ai_flags_1 (out, ai, flag, #flag, &flags_printed) ++ FLAG (AI_PASSIVE); ++ FLAG (AI_CANONNAME); ++ FLAG (AI_NUMERICHOST); ++ FLAG (AI_V4MAPPED); ++ FLAG (AI_ALL); ++ FLAG (AI_ADDRCONFIG); ++ FLAG (AI_IDN); ++ FLAG (AI_CANONIDN); ++ FLAG (AI_IDN_ALLOW_UNASSIGNED); ++ FLAG (AI_IDN_USE_STD3_ASCII_RULES); ++ FLAG (AI_NUMERICSERV); ++#undef FLAG ++ int remaining = ai->ai_flags & ~flags_printed; ++ if (remaining != 0) ++ fprintf (out, " %08x", remaining); ++ fprintf (out, "\n"); ++ } ++ ++ /* 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; ++ char proto_buf[32]; ++ const char *proto_str; ++ ++ /* ai_socktype */ ++ switch (ai->ai_socktype) ++ { ++ case SOCK_RAW: ++ type_str = "RAW"; ++ break; ++ case SOCK_DGRAM: ++ type_str = "DGRAM"; ++ break; ++ case SOCK_STREAM: ++ type_str = "STREAM"; ++ break; ++ default: ++ snprintf (type_buf, sizeof (type_buf), "%d", ai->ai_socktype); ++ type_str = type_buf; ++ } ++ ++ /* ai_protocol */ ++ switch (ai->ai_protocol) ++ { ++ case IPPROTO_IP: ++ proto_str = "IP"; ++ break; ++ case IPPROTO_UDP: ++ proto_str = "UDP"; ++ break; ++ case IPPROTO_TCP: ++ proto_str = "TCP"; ++ break; ++ default: ++ snprintf (proto_buf, sizeof (proto_buf), "%d", ai->ai_protocol); ++ proto_str = proto_buf; ++ } ++ fprintf (out, "address: %s/%s", type_str, proto_str); ++ } ++ ++ /* ai_addrlen */ ++ if (ai->ai_addrlen != socket_address_length (ai->ai_family)) ++ { ++ char *family = support_format_address_family (ai->ai_family); ++ fprintf (out, "error: invalid address length %d for %s\n", ++ ai->ai_addrlen, family); ++ free (family); ++ } ++ ++ /* ai_addr */ ++ { ++ char buf[128]; ++ uint16_t port; ++ const char *ret; ++ switch (ai->ai_family) ++ { ++ case AF_INET: ++ { ++ struct sockaddr_in *sin = (struct sockaddr_in *) ai->ai_addr; ++ ret = inet_ntop (AF_INET, &sin->sin_addr, buf, sizeof (buf)); ++ port = sin->sin_port; ++ } ++ break; ++ case AF_INET6: ++ { ++ struct sockaddr_in6 *sin = (struct sockaddr_in6 *) ai->ai_addr; ++ ret = inet_ntop (AF_INET6, &sin->sin6_addr, buf, sizeof (buf)); ++ port = sin->sin6_port; ++ } ++ break; ++ default: ++ errno = EAFNOSUPPORT; ++ ret = NULL; ++ } ++ if (ret == NULL) ++ fprintf (out, "error: inet_top failed: %m\n"); ++ else ++ fprintf (out, " %s %u\n", buf, ntohs (port)); ++ } ++} ++ ++/* Format all the addresses in one address family. */ ++static void ++format_ai_family (FILE *out, struct addrinfo *ai, int family) ++{ ++ while (ai) ++ { ++ if (ai->ai_family == family) ++ format_ai_one (out, ai); ++ ai = ai->ai_next; ++ } ++} ++ ++char * ++support_format_addrinfo (struct addrinfo *ai, int ret) ++{ ++ int errno_copy = errno; ++ ++ struct xmemstream mem; ++ xopen_memstream (&mem); ++ if (ret != 0) ++ { ++ fprintf (mem.out, "error: %s\n", gai_strerror (ret)); ++ if (ret == EAI_SYSTEM) ++ { ++ errno = errno_copy; ++ fprintf (mem.out, "error: %m\n"); ++ } ++ } ++ else ++ { ++ 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); ++ return mem.buffer; ++} +diff --git a/support/support_format_dns_packet.c b/support/support_format_dns_packet.c +new file mode 100644 +index 0000000000..2992c57971 +--- /dev/null ++++ b/support/support_format_dns_packet.c +@@ -0,0 +1,222 @@ ++/* Convert a DNS packet to a human-readable representation. ++ 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 ++ ++struct in_buffer ++{ ++ const unsigned char *data; ++ size_t size; ++}; ++ ++static inline bool ++extract_8 (struct in_buffer *in, unsigned char *value) ++{ ++ if (in->size == 0) ++ return false; ++ *value = in->data[0]; ++ ++in->data; ++ --in->size; ++ return true; ++} ++ ++static inline bool ++extract_16 (struct in_buffer *in, unsigned short *value) ++{ ++ if (in->size < 2) ++ return false; ++ *value = (in->data[0] << 8) | in->data[1]; ++ in->data += 2; ++ in->size -= 2; ++ return true; ++} ++ ++static inline bool ++extract_32 (struct in_buffer *in, unsigned *value) ++{ ++ if (in->size < 4) ++ return false; ++ unsigned a = in->data[0]; ++ unsigned b = in->data[1]; ++ unsigned c = in->data[2]; ++ unsigned d = in->data[3]; ++ *value = (a << 24) | (b << 16) | (c << 8) | d; ++ in->data += 4; ++ in->size -= 4; ++ return true; ++} ++ ++static inline bool ++extract_bytes (struct in_buffer *in, size_t length, struct in_buffer *value) ++{ ++ if (in->size < length) ++ return false; ++ *value = (struct in_buffer) {in->data, length}; ++ in->data += length; ++ in->size -= length; ++ return true; ++} ++ ++struct dname ++{ ++ char name[MAXDNAME + 1]; ++}; ++ ++static bool ++extract_name (struct in_buffer full, struct in_buffer *in, struct dname *value) ++{ ++ const unsigned char *full_end = full.data + full.size; ++ /* Sanity checks; these indicate buffer misuse. */ ++ TEST_VERIFY_EXIT ++ (!(in->data < full.data || in->data > full_end ++ || in->size > (size_t) (full_end - in->data))); ++ int ret = dn_expand (full.data, full_end, in->data, ++ value->name, sizeof (value->name)); ++ if (ret < 0) ++ return false; ++ in->data += ret; ++ in->size -= ret; ++ return true; ++} ++ ++char * ++support_format_dns_packet (const unsigned char *buffer, size_t length) ++{ ++ struct in_buffer full = { buffer, length }; ++ struct in_buffer in = full; ++ struct xmemstream mem; ++ xopen_memstream (&mem); ++ ++ unsigned short txnid; ++ unsigned short flags; ++ unsigned short qdcount; ++ unsigned short ancount; ++ unsigned short nscount; ++ unsigned short adcount; ++ if (!(extract_16 (&in, &txnid) ++ && extract_16 (&in, &flags) ++ && extract_16 (&in, &qdcount) ++ && extract_16 (&in, &ancount) ++ && extract_16 (&in, &nscount) ++ && extract_16 (&in, &adcount))) ++ { ++ fprintf (mem.out, "error: could not parse DNS header\n"); ++ goto out; ++ } ++ if (qdcount != 1) ++ { ++ fprintf (mem.out, "error: question count is %d, not 1\n", qdcount); ++ goto out; ++ } ++ struct dname qname; ++ if (!extract_name (full, &in, &qname)) ++ { ++ fprintf (mem.out, "error: malformed QNAME\n"); ++ goto out; ++ } ++ unsigned short qtype; ++ unsigned short qclass; ++ if (!(extract_16 (&in, &qtype) ++ && extract_16 (&in, &qclass))) ++ { ++ fprintf (mem.out, "error: malformed question\n"); ++ goto out; ++ } ++ if (qtype != T_A && qtype != T_AAAA && qtype != T_PTR) ++ { ++ fprintf (mem.out, "error: unsupported QTYPE %d\n", qtype); ++ goto out; ++ } ++ ++ fprintf (mem.out, "name: %s\n", qname.name); ++ ++ for (int i = 0; i < ancount; ++i) ++ { ++ struct dname rname; ++ if (!extract_name (full, &in, &rname)) ++ { ++ fprintf (mem.out, "error: malformed record name\n"); ++ goto out; ++ } ++ unsigned short rtype; ++ unsigned short rclass; ++ unsigned ttl; ++ unsigned short rdlen; ++ struct in_buffer rdata; ++ if (!(extract_16 (&in, &rtype) ++ && extract_16 (&in, &rclass) ++ && extract_32 (&in, &ttl) ++ && extract_16 (&in, &rdlen) ++ && extract_bytes (&in, rdlen, &rdata))) ++ { ++ fprintf (mem.out, "error: malformed record header\n"); ++ goto out; ++ } ++ /* Skip non-matching record types. */ ++ if ((rtype != qtype && rtype != T_CNAME) || rclass != qclass) ++ continue; ++ switch (rtype) ++ { ++ case T_A: ++ if (rdlen == 4) ++ fprintf (mem.out, "address: %d.%d.%d.%d\n", ++ rdata.data[0], ++ rdata.data[1], ++ rdata.data[2], ++ rdata.data[3]); ++ else ++ fprintf (mem.out, "error: A record of size %d: %s\n", ++ rdlen, rname.name); ++ break; ++ case T_AAAA: ++ { ++ 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, "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, &rdata, &name)) ++ fprintf (mem.out, "name: %s\n", name.name); ++ else ++ fprintf (mem.out, "error: malformed CNAME/PTR record\n"); ++ } ++ } ++ } ++ ++ out: ++ xfclose_memstream (&mem); ++ return mem.buffer; ++} +diff --git a/support/support_format_herrno.c b/support/support_format_herrno.c +new file mode 100644 +index 0000000000..493d6ae962 +--- /dev/null ++++ b/support/support_format_herrno.c +@@ -0,0 +1,45 @@ ++/* Convert a h_errno error code to a string. ++ 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 ++ ++char * ++support_format_herrno (int code) ++{ ++ const char *errstr; ++ switch (code) ++ { ++ case HOST_NOT_FOUND: ++ errstr = "HOST_NOT_FOUND"; ++ break; ++ case NO_ADDRESS: ++ errstr = "NO_ADDRESS"; ++ break; ++ case NO_RECOVERY: ++ errstr = "NO_RECOVERY"; ++ break; ++ case TRY_AGAIN: ++ errstr = "TRY_AGAIN"; ++ break; ++ default: ++ return xasprintf ("\n", code); ++ } ++ return xstrdup (errstr); ++} +diff --git a/support/support_format_hostent.c b/support/support_format_hostent.c +new file mode 100644 +index 0000000000..5b5f26082e +--- /dev/null ++++ b/support/support_format_hostent.c +@@ -0,0 +1,75 @@ ++/* Convert a struct hostent object to a string. ++ 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 ++ ++static int ++address_length (int family) ++{ ++ switch (family) ++ { ++ case AF_INET: ++ return 4; ++ case AF_INET6: ++ return 16; ++ } ++ return -1; ++} ++ ++char * ++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; ++ } ++ ++ struct xmemstream mem; ++ xopen_memstream (&mem); ++ ++ fprintf (mem.out, "name: %s\n", h->h_name); ++ for (char **alias = h->h_aliases; *alias != NULL; ++alias) ++ fprintf (mem.out, "alias: %s\n", *alias); ++ for (unsigned i = 0; h->h_addr_list[i] != NULL; ++i) ++ { ++ char buf[128]; ++ if (inet_ntop (h->h_addrtype, h->h_addr_list[i], ++ buf, sizeof (buf)) == NULL) ++ fprintf (mem.out, "error: inet_ntop failed: %m\n"); ++ else ++ fprintf (mem.out, "address: %s\n", buf); ++ } ++ if (h->h_length != address_length (h->h_addrtype)) ++ { ++ char *family = support_format_address_family (h->h_addrtype); ++ fprintf (mem.out, "error: invalid address length %d for %s\n", ++ h->h_length, family); ++ free (family); ++ } ++ ++ xfclose_memstream (&mem); ++ return mem.buffer; ++} +diff --git a/support/support_format_netent.c b/support/support_format_netent.c +new file mode 100644 +index 0000000000..020f5720d9 +--- /dev/null ++++ b/support/support_format_netent.c +@@ -0,0 +1,52 @@ ++/* Convert a struct netent object to a string. ++ 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 ++ ++char * ++support_format_netent (struct netent *e) ++{ ++ if (e == NULL) ++ { ++ char *value = support_format_herrno (h_errno); ++ char *result = xasprintf ("error: %s\n", value); ++ free (value); ++ return result; ++ } ++ ++ struct xmemstream mem; ++ xopen_memstream (&mem); ++ ++ if (e->n_name != NULL) ++ fprintf (mem.out, "name: %s\n", e->n_name); ++ for (char **ap = e->n_aliases; *ap != NULL; ++ap) ++ fprintf (mem.out, "alias: %s\n", *ap); ++ if (e->n_addrtype != AF_INET) ++ fprintf (mem.out, "addrtype: %d\n", e->n_addrtype); ++ /* On alpha, e->n_net is an unsigned long. */ ++ unsigned int n_net = e->n_net; ++ fprintf (mem.out, "net: 0x%08x\n", n_net); ++ ++ xfclose_memstream (&mem); ++ return mem.buffer; ++} +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_record_failure.c b/support/support_record_failure.c +new file mode 100644 +index 0000000000..684055c746 +--- /dev/null ++++ b/support/support_record_failure.c +@@ -0,0 +1,106 @@ ++/* Global test failure counter. ++ 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 ++ ++/* This structure keeps track of test failures. The counter is ++ incremented on each failure. The failed member is set to true if a ++ failure is detected, so that even if the counter wraps around to ++ zero, the failure of a test can be detected. ++ ++ The init constructor function below puts *state on a shared ++ annonymous mapping, so that failure reports from subprocesses ++ propagate to the parent process. */ ++struct test_failures ++{ ++ unsigned int counter; ++ unsigned int failed; ++}; ++static struct test_failures *state; ++ ++static __attribute__ ((constructor)) void ++init (void) ++{ ++ void *ptr = mmap (NULL, sizeof (*state), PROT_READ | PROT_WRITE, ++ MAP_ANONYMOUS | MAP_SHARED, -1, 0); ++ if (ptr == MAP_FAILED) ++ { ++ printf ("error: could not map %zu bytes: %m\n", sizeof (*state)); ++ exit (1); ++ } ++ /* Zero-initialization of the struct is sufficient. */ ++ state = ptr; ++} ++ ++void ++support_record_failure (void) ++{ ++ if (state == NULL) ++ { ++ write_message ++ ("error: support_record_failure called without initialization\n"); ++ _exit (1); ++ } ++ /* Relaxed MO is sufficient because we are only interested in the ++ values themselves, in isolation. */ ++ __atomic_store_n (&state->failed, 1, __ATOMIC_RELEASE); ++ __atomic_add_fetch (&state->counter, 1, __ATOMIC_RELEASE); ++} ++ ++int ++support_report_failure (int status) ++{ ++ if (state == NULL) ++ { ++ write_message ++ ("error: support_report_failure called without initialization\n"); ++ return 1; ++ } ++ ++ /* Relaxed MO is sufficient because acquire test result reporting ++ assumes that exiting from the main thread happens before the ++ error reporting via support_record_failure, which requires some ++ form of external synchronization. */ ++ bool failed = __atomic_load_n (&state->failed, __ATOMIC_RELAXED); ++ if (failed) ++ printf ("error: %u test failures\n", ++ __atomic_load_n (&state->counter, __ATOMIC_RELAXED)); ++ ++ if ((status == 0 || status == EXIT_UNSUPPORTED) && failed) ++ /* If we have a recorded failure, it overrides a non-failure ++ report from the test function. */ ++ status = 1; ++ return status; ++} ++ ++void ++support_record_failure_reset (void) ++{ ++ /* Only used for testing the test framework, with external ++ synchronization, but use release MO for consistency. */ ++ __atomic_store_n (&state->failed, 0, __ATOMIC_RELAXED); ++ __atomic_add_fetch (&state->counter, 0, __ATOMIC_RELAXED); ++} +diff --git a/support/support_run_diff.c b/support/support_run_diff.c +new file mode 100644 +index 0000000000..f5155de727 +--- /dev/null ++++ b/support/support_run_diff.c +@@ -0,0 +1,76 @@ ++/* Invoke the system diff tool to compare two strings. ++ 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 ++ ++static char * ++write_to_temp_file (const char *prefix, const char *str) ++{ ++ char *template = xasprintf ("run_diff-%s", prefix); ++ char *name = NULL; ++ int fd = create_temp_file (template, &name); ++ TEST_VERIFY_EXIT (fd >= 0); ++ free (template); ++ xwrite (fd, str, strlen (str)); ++ xclose (fd); ++ return name; ++} ++ ++void ++support_run_diff (const char *left_label, const char *left, ++ const char *right_label, const char *right) ++{ ++ /* Ensure that the diff command output is ordered properly with ++ standard output. */ ++ TEST_VERIFY_EXIT (fflush (stdout) == 0); ++ ++ char *left_path = write_to_temp_file ("left-diff", left); ++ char *right_path = write_to_temp_file ("right-diff", right); ++ ++ pid_t pid = xfork (); ++ if (pid == 0) ++ { ++ execlp ("diff", "diff", "-u", ++ "--label", left_label, "--label", right_label, ++ "--", left_path, right_path, ++ NULL); ++ _exit (17); ++ } ++ else ++ { ++ int status; ++ xwaitpid (pid, &status, 0); ++ if (!WIFEXITED (status) || WEXITSTATUS (status) != 1) ++ printf ("warning: could not run diff, exit status: %d\n" ++ "*** %s ***\n%s\n" ++ "*** %s ***\n%s\n", ++ status, left_label, left, right_label, right); ++ } ++ ++ free (right_path); ++ free (left_path); ++} +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 +new file mode 100644 +index 0000000000..914d64f603 +--- /dev/null ++++ b/support/support_test_main.c +@@ -0,0 +1,423 @@ ++/* Main worker function for the test driver. ++ Copyright (C) 1998-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 ++#include ++#include ++#include ++#include ++ ++static const struct option default_options[] = ++{ ++ TEST_DEFAULT_OPTIONS ++ { NULL, 0, NULL, 0 } ++}; ++ ++/* Show people how to run the program. */ ++static void ++usage (const struct option *options) ++{ ++ size_t i; ++ ++ printf ("Usage: %s [options]\n" ++ "\n" ++ "Environment Variables:\n" ++ " TIMEOUTFACTOR An integer used to scale the timeout\n" ++ " TMPDIR Where to place temporary files\n" ++ " TEST_COREDUMPS Do not disable coredumps if set\n" ++ "\n", ++ program_invocation_short_name); ++ printf ("Options:\n"); ++ for (i = 0; options[i].name; ++i) ++ { ++ int indent; ++ ++ indent = printf (" --%s", options[i].name); ++ if (options[i].has_arg == required_argument) ++ indent += printf (" "); ++ printf ("%*s", 25 - indent, ""); ++ switch (options[i].val) ++ { ++ case 'v': ++ printf ("Increase the output verbosity"); ++ break; ++ case OPT_DIRECT: ++ printf ("Run the test directly (instead of forking & monitoring)"); ++ break; ++ case OPT_TESTDIR: ++ printf ("Override the TMPDIR env var"); ++ break; ++ } ++ printf ("\n"); ++ } ++} ++ ++/* The PID of the test process. */ ++static pid_t test_pid; ++ ++/* The cleanup handler passed to test_main. */ ++static void (*cleanup_function) (void); ++ ++/* Timeout handler. We kill the child and exit with an error. */ ++static void ++__attribute__ ((noreturn)) ++signal_handler (int sig) ++{ ++ int killed; ++ int status; ++ ++ assert (test_pid > 1); ++ /* Kill the whole process group. */ ++ kill (-test_pid, SIGKILL); ++ /* In case setpgid failed in the child, kill it individually too. */ ++ kill (test_pid, SIGKILL); ++ ++ /* Wait for it to terminate. */ ++ int i; ++ for (i = 0; i < 5; ++i) ++ { ++ killed = waitpid (test_pid, &status, WNOHANG|WUNTRACED); ++ if (killed != 0) ++ break; ++ ++ /* Delay, give the system time to process the kill. If the ++ nanosleep() call return prematurely, all the better. We ++ won't restart it since this probably means the child process ++ finally died. */ ++ struct timespec ts; ++ ts.tv_sec = 0; ++ ts.tv_nsec = 100000000; ++ nanosleep (&ts, NULL); ++ } ++ if (killed != 0 && killed != test_pid) ++ { ++ printf ("Failed to kill test process: %m\n"); ++ exit (1); ++ } ++ ++ if (cleanup_function != NULL) ++ cleanup_function (); ++ ++ if (sig == SIGINT) ++ { ++ signal (sig, SIG_DFL); ++ raise (sig); ++ } ++ ++ if (killed == 0 || (WIFSIGNALED (status) && WTERMSIG (status) == SIGKILL)) ++ puts ("Timed out: killed the child process"); ++ else if (WIFSTOPPED (status)) ++ printf ("Timed out: the child process was %s\n", ++ strsignal (WSTOPSIG (status))); ++ else if (WIFSIGNALED (status)) ++ printf ("Timed out: the child process got signal %s\n", ++ strsignal (WTERMSIG (status))); ++ else ++ printf ("Timed out: killed the child process but it exited %d\n", ++ WEXITSTATUS (status)); ++ ++ /* Exit with an error. */ ++ exit (1); ++} ++ ++/* Run test_function or test_function_argv. */ ++static int ++run_test_function (int argc, char **argv, const struct test_config *config) ++{ ++ if (config->test_function != NULL) ++ return config->test_function (); ++ else if (config->test_function_argv != NULL) ++ return config->test_function_argv (argc, argv); ++ else ++ { ++ printf ("error: no test function defined\n"); ++ exit (1); ++ } ++} ++ ++static bool test_main_called; ++ ++const char *test_dir = NULL; ++unsigned int test_verbose = 0; ++ ++/* If test failure reporting has been linked in, it may contribute ++ additional test failures. */ ++static int ++adjust_exit_status (int status) ++{ ++ if (support_report_failure != NULL) ++ return support_report_failure (status); ++ return status; ++} ++ ++int ++support_test_main (int argc, char **argv, const struct test_config *config) ++{ ++ if (test_main_called) ++ { ++ printf ("error: test_main called for a second time\n"); ++ exit (1); ++ } ++ test_main_called = true; ++ const struct option *options; ++ if (config->options != NULL) ++ options = config->options; ++ else ++ options = default_options; ++ ++ cleanup_function = config->cleanup_function; ++ ++ int direct = 0; /* Directly call the test function? */ ++ int status; ++ int opt; ++ unsigned int timeoutfactor = 1; ++ pid_t termpid; ++ ++ if (!config->no_mallopt) ++ { ++ /* Make uses of freed and uninitialized memory known. Do not ++ pull in a definition for mallopt if it has not been defined ++ already. */ ++ extern __typeof__ (mallopt) mallopt __attribute__ ((weak)); ++ if (mallopt != NULL) ++ mallopt (M_PERTURB, 42); ++ } ++ ++ while ((opt = getopt_long (argc, argv, "+", options, NULL)) != -1) ++ switch (opt) ++ { ++ case '?': ++ usage (options); ++ exit (1); ++ case 'v': ++ ++test_verbose; ++ break; ++ case OPT_DIRECT: ++ direct = 1; ++ break; ++ case OPT_TESTDIR: ++ test_dir = optarg; ++ break; ++ default: ++ if (config->cmdline_function != NULL) ++ config->cmdline_function (opt); ++ } ++ ++ /* If set, read the test TIMEOUTFACTOR value from the environment. ++ This value is used to scale the default test timeout values. */ ++ char *envstr_timeoutfactor = getenv ("TIMEOUTFACTOR"); ++ if (envstr_timeoutfactor != NULL) ++ { ++ char *envstr_conv = envstr_timeoutfactor; ++ unsigned long int env_fact; ++ ++ env_fact = strtoul (envstr_timeoutfactor, &envstr_conv, 0); ++ if (*envstr_conv == '\0' && envstr_conv != envstr_timeoutfactor) ++ timeoutfactor = MAX (env_fact, 1); ++ } ++ ++ /* Set TMPDIR to specified test directory. */ ++ if (test_dir != NULL) ++ { ++ setenv ("TMPDIR", test_dir, 1); ++ ++ if (chdir (test_dir) < 0) ++ { ++ printf ("chdir: %m\n"); ++ exit (1); ++ } ++ } ++ else ++ { ++ test_dir = getenv ("TMPDIR"); ++ if (test_dir == NULL || test_dir[0] == '\0') ++ test_dir = "/tmp"; ++ } ++ if (support_set_test_dir != NULL) ++ support_set_test_dir (test_dir); ++ ++ int timeout = config->timeout; ++ if (timeout == 0) ++ timeout = DEFAULT_TIMEOUT; ++ ++ /* Make sure we see all message, even those on stdout. */ ++ setvbuf (stdout, NULL, _IONBF, 0); ++ ++ /* Make sure temporary files are deleted. */ ++ if (support_delete_temp_files != NULL) ++ atexit (support_delete_temp_files); ++ ++ /* Correct for the possible parameters. */ ++ argv[optind - 1] = argv[0]; ++ argv += optind - 1; ++ argc -= optind - 1; ++ ++ /* Call the initializing function, if one is available. */ ++ if (config->prepare_function != NULL) ++ config->prepare_function (argc, argv); ++ ++ const char *envstr_direct = getenv ("TEST_DIRECT"); ++ if (envstr_direct != NULL) ++ { ++ FILE *f = fopen (envstr_direct, "w"); ++ if (f == NULL) ++ { ++ printf ("cannot open TEST_DIRECT output file '%s': %m\n", ++ envstr_direct); ++ exit (1); ++ } ++ ++ fprintf (f, "timeout=%u\ntimeoutfactor=%u\n", ++ config->timeout, timeoutfactor); ++ if (config->expected_status != 0) ++ fprintf (f, "exit=%u\n", config->expected_status); ++ if (config->expected_signal != 0) ++ fprintf (f, "signal=%s\n", strsignal (config->expected_signal)); ++ ++ if (support_print_temp_files != NULL) ++ support_print_temp_files (f); ++ ++ fclose (f); ++ direct = 1; ++ } ++ ++ bool disable_coredumps; ++ { ++ const char *coredumps = getenv ("TEST_COREDUMPS"); ++ disable_coredumps = coredumps == NULL || coredumps[0] == '\0'; ++ } ++ ++ /* If we are not expected to fork run the function immediately. */ ++ if (direct) ++ return adjust_exit_status (run_test_function (argc, argv, config)); ++ ++ /* Set up the test environment: ++ - prevent core dumps ++ - set up the timer ++ - fork and execute the function. */ ++ ++ test_pid = fork (); ++ if (test_pid == 0) ++ { ++ /* This is the child. */ ++ if (disable_coredumps) ++ { ++ /* Try to avoid dumping core. This is necessary because we ++ run the test from the source tree, and the coredumps ++ would end up there (and not in the build tree). */ ++ struct rlimit core_limit; ++ core_limit.rlim_cur = 0; ++ core_limit.rlim_max = 0; ++ setrlimit (RLIMIT_CORE, &core_limit); ++ } ++ ++ /* We put the test process in its own pgrp so that if it bogusly ++ generates any job control signals, they won't hit the whole build. */ ++ if (setpgid (0, 0) != 0) ++ printf ("Failed to set the process group ID: %m\n"); ++ ++ /* Execute the test function and exit with the return value. */ ++ exit (run_test_function (argc, argv, config)); ++ } ++ else if (test_pid < 0) ++ { ++ printf ("Cannot fork test program: %m\n"); ++ exit (1); ++ } ++ ++ /* Set timeout. */ ++ signal (SIGALRM, signal_handler); ++ alarm (timeout * timeoutfactor); ++ ++ /* Make sure we clean up if the wrapper gets interrupted. */ ++ signal (SIGINT, signal_handler); ++ ++ /* Wait for the regular termination. */ ++ termpid = TEMP_FAILURE_RETRY (waitpid (test_pid, &status, 0)); ++ if (termpid == -1) ++ { ++ printf ("Waiting for test program failed: %m\n"); ++ exit (1); ++ } ++ if (termpid != test_pid) ++ { ++ printf ("Oops, wrong test program terminated: expected %ld, got %ld\n", ++ (long int) test_pid, (long int) termpid); ++ exit (1); ++ } ++ ++ /* Process terminated normaly without timeout etc. */ ++ if (WIFEXITED (status)) ++ { ++ if (config->expected_status == 0) ++ { ++ if (config->expected_signal == 0) ++ /* Exit with the return value of the test. */ ++ return adjust_exit_status (WEXITSTATUS (status)); ++ else ++ { ++ printf ("Expected signal '%s' from child, got none\n", ++ strsignal (config->expected_signal)); ++ exit (1); ++ } ++ } ++ else ++ { ++ /* Non-zero exit status is expected */ ++ if (WEXITSTATUS (status) != config->expected_status) ++ { ++ printf ("Expected status %d, got %d\n", ++ config->expected_status, WEXITSTATUS (status)); ++ exit (1); ++ } ++ } ++ return adjust_exit_status (0); ++ } ++ /* Process was killed by timer or other signal. */ ++ else ++ { ++ if (config->expected_signal == 0) ++ { ++ printf ("Didn't expect signal from child: got `%s'\n", ++ strsignal (WTERMSIG (status))); ++ exit (1); ++ } ++ else if (WTERMSIG (status) != config->expected_signal) ++ { ++ printf ("Incorrect signal from child: got `%s', need `%s'\n", ++ strsignal (WTERMSIG (status)), ++ strsignal (config->expected_signal)); ++ exit (1); ++ } ++ ++ return adjust_exit_status (0); ++ } ++} +diff --git a/support/support_test_verify_impl.c b/support/support_test_verify_impl.c +new file mode 100644 +index 0000000000..5bae38f8b1 +--- /dev/null ++++ b/support/support_test_verify_impl.c +@@ -0,0 +1,33 @@ ++/* Implementation of the TEST_VERIFY and TEST_VERIFY_EXIT macros. ++ 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 ++ ++void ++support_test_verify_impl (int status, 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); ++ ++} +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-internal.h b/support/temp_file-internal.h +new file mode 100644 +index 0000000000..fb6cceb065 +--- /dev/null ++++ b/support/temp_file-internal.h +@@ -0,0 +1,31 @@ ++/* Internal weak declarations for temporary file handling. ++ 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 ++ . */ ++ ++#ifndef SUPPORT_TEMP_FILE_INTERNAL_H ++#define SUPPORT_TEMP_FILE_INTERNAL_H ++ ++/* These functions are called by the test driver if they are ++ defined. Tests should not call them directly. */ ++ ++#include ++ ++void support_set_test_dir (const char *name) __attribute__ ((weak)); ++void support_delete_temp_files (void) __attribute__ ((weak)); ++void support_print_temp_files (FILE *) __attribute__ ((weak)); ++ ++#endif /* SUPPORT_TEMP_FILE_INTERNAL_H */ +diff --git a/support/temp_file.c b/support/temp_file.c +new file mode 100644 +index 0000000000..fdb2477ab9 +--- /dev/null ++++ b/support/temp_file.c +@@ -0,0 +1,132 @@ ++/* Temporary file handling for tests. ++ Copyright (C) 1998-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 is required to get an mkstemp which can create large files on ++ some 32-bit platforms. */ ++#define _FILE_OFFSET_BITS 64 ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* List of temporary files. */ ++static struct temp_name_list ++{ ++ struct temp_name_list *next; ++ char *name; ++ pid_t owner; ++} *temp_name_list; ++ ++/* Location of the temporary files. Set by the test skeleton via ++ support_set_test_dir. The string is not be freed. */ ++static const char *test_dir = _PATH_TMP; ++ ++void ++add_temp_file (const char *name) ++{ ++ struct temp_name_list *newp ++ = (struct temp_name_list *) xcalloc (sizeof (*newp), 1); ++ char *newname = strdup (name); ++ if (newname != NULL) ++ { ++ newp->name = newname; ++ newp->next = temp_name_list; ++ newp->owner = getpid (); ++ temp_name_list = newp; ++ } ++ else ++ free (newp); ++} ++ ++int ++create_temp_file (const char *base, char **filename) ++{ ++ char *fname; ++ int fd; ++ ++ fname = (char *) xmalloc (strlen (test_dir) + 1 + strlen (base) ++ + sizeof ("XXXXXX")); ++ strcpy (stpcpy (stpcpy (stpcpy (fname, test_dir), "/"), base), "XXXXXX"); ++ ++ fd = mkstemp (fname); ++ if (fd == -1) ++ { ++ printf ("cannot open temporary file '%s': %m\n", fname); ++ free (fname); ++ return -1; ++ } ++ ++ add_temp_file (fname); ++ if (filename != NULL) ++ *filename = fname; ++ else ++ free (fname); ++ ++ return fd; ++} ++ ++/* Helper functions called by the test skeleton follow. */ ++ ++void ++support_set_test_dir (const char *path) ++{ ++ test_dir = path; ++} ++ ++void ++support_delete_temp_files (void) ++{ ++ pid_t pid = getpid (); ++ while (temp_name_list != NULL) ++ { ++ /* 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 = temp_name_list->next; ++ free (temp_name_list); ++ temp_name_list = next; ++ } ++} ++ ++void ++support_print_temp_files (FILE *f) ++{ ++ if (temp_name_list != NULL) ++ { ++ struct temp_name_list *n; ++ fprintf (f, "temp_files=(\n"); ++ for (n = temp_name_list; n != NULL; n = n->next) ++ fprintf (f, " '%s'\n", n->name); ++ fprintf (f, ")\n"); ++ } ++} +diff --git a/support/temp_file.h b/support/temp_file.h +new file mode 100644 +index 0000000000..6fed8df1ea +--- /dev/null ++++ b/support/temp_file.h +@@ -0,0 +1,37 @@ ++/* Declarations for temporary file handling. ++ 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 ++ . */ ++ ++#ifndef SUPPORT_TEMP_FILE_H ++#define SUPPORT_TEMP_FILE_H ++ ++#include ++ ++__BEGIN_DECLS ++ ++/* Schedule a temporary file for deletion on exit. */ ++void add_temp_file (const char *name); ++ ++/* Create a temporary file. Return the opened file descriptor on ++ success, or -1 on failure. Write the file name to *FILENAME if ++ FILENAME is not NULL. In this case, the caller is expected to free ++ *FILENAME. */ ++int create_temp_file (const char *base, char **filename); ++ ++__END_DECLS ++ ++#endif /* SUPPORT_TEMP_FILE_H */ +diff --git a/support/test-driver.c b/support/test-driver.c +new file mode 100644 +index 0000000000..482066dbeb +--- /dev/null ++++ b/support/test-driver.c +@@ -0,0 +1,156 @@ ++/* Main function for test programs. ++ 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 ++ . */ ++ ++/* This file should be included from test cases. It will define a ++ main function which provides the test wrapper. ++ ++ It assumes that the test case defines a function ++ ++ int do_test (void); ++ ++ and arranges for that function being called under the test wrapper. ++ The do_test function should return 0 to indicate a passing test, 1 ++ to indicate a failing test, or 77 to indicate an unsupported test. ++ Other result values could be used to indicate a failing test, but ++ the result of the expression is passed to exit and exit only ++ returns the lower 8 bits of its input. A non-zero return with some ++ values could cause a test to incorrectly be considered passing when ++ it really failed. For this reason, the function should always ++ return 0 (EXIT_SUCCESS), 1 (EXIT_FAILURE), or 77 ++ (EXIT_UNSUPPORTED). ++ ++ The test function may print out diagnostic or warning messages as well ++ as messages about failures. These messages should be printed to stdout ++ and not stderr so that the output is properly ordered with respect to ++ the rest of the glibc testsuite run output. ++ ++ Several preprocessors macros can be defined before including this ++ file. ++ ++ The name of the do_test function can be changed with the ++ TEST_FUNCTION macro. It must expand to the desired function name. ++ ++ If the test case needs access to command line parameters, it must ++ define the TEST_FUNCTION_ARGV macro with the name of the test ++ function. It must have the following type: ++ ++ int TEST_FUNCTION_ARGV (int argc, char **argv); ++ ++ This overrides the do_test default function and is incompatible ++ with the TEST_FUNCTION macro. ++ ++ If PREPARE is defined, it must expand to the name of a function of ++ the type ++ ++ void PREPARE (int argc, char **); ++ ++ This function will be called early, after parsing the command line, ++ but before running the test, in the parent process which acts as ++ the test supervisor. ++ ++ If CLEANUP_HANDLER is defined, it must expand to the name of a ++ function of the type ++ ++ void CLEANUP_HANDLER (void); ++ ++ This function will be called from the timeout (SIGALRM) signal ++ handler. ++ ++ If EXPECTED_SIGNAL is defined, it must expanded to a constant which ++ denotes the expected signal number. ++ ++ If EXPECTED_STATUS is defined, it must expand to the expected exit ++ status. ++ ++ If TIMEOUT is defined, it must be positive constant. It overrides ++ the default test timeout and is measured in seconds. ++ ++ If TEST_NO_MALLOPT is defined, the test wrapper will not call ++ mallopt. ++ ++ Custom command line handling can be implemented by defining the ++ CMDLINE_OPTION macro (after including the header; this ++ requires _GNU_SOURCE to be defined). This macro must expand to a ++ to a comma-separated list of braced initializers for struct option ++ from , with a trailing comma. CMDLINE_PROCESS can be ++ defined as the name of a function which is called to process these ++ options. The function is passed the option character/number and ++ has this type: ++ ++ void CMDLINE_PROCESS (int); ++*/ ++ ++#include ++ ++#include ++ ++int ++main (int argc, char **argv) ++{ ++ struct test_config test_config; ++ memset (&test_config, 0, sizeof (test_config)); ++ ++#ifdef PREPARE ++ test_config.prepare_function = (PREPARE); ++#endif ++ ++#if defined (TEST_FUNCTION) && defined (TEST_FUNCTON_ARGV) ++# error TEST_FUNCTION and TEST_FUNCTION_ARGV cannot be defined at the same time ++#endif ++#if defined (TEST_FUNCTION) ++ test_config.test_function = TEST_FUNCTION; ++#elif defined (TEST_FUNCTION_ARGV) ++ test_config.test_function_argv = TEST_FUNCTION_ARGV; ++#else ++ test_config.test_function = do_test; ++#endif ++ ++#ifdef CLEANUP_HANDLER ++ test_config.cleanup_function = CLEANUP_HANDLER; ++#endif ++ ++#ifdef EXPECTED_SIGNAL ++ test_config.expected_signal = (EXPECTED_SIGNAL); ++#endif ++ ++#ifdef EXPECTED_STATUS ++ test_config.expected_status = (EXPECTED_STATUS); ++#endif ++ ++#ifdef TEST_NO_MALLOPT ++ test_config.no_mallopt = 1; ++#endif ++ ++#ifdef TIMEOUT ++ test_config.timeout = TIMEOUT; ++#endif ++ ++#ifdef CMDLINE_OPTIONS ++ struct option options[] = ++ { ++ CMDLINE_OPTIONS ++ TEST_DEFAULT_OPTIONS ++ }; ++ test_config.options = &options; ++#endif ++#ifdef CMDLINE_PROCESS ++ test_config.cmdline_function = CMDLINE_PROCESS; ++#endif ++ ++ return support_test_main (argc, argv, &test_config); ++} +diff --git a/support/test-driver.h b/support/test-driver.h +new file mode 100644 +index 0000000000..af1971a9ca +--- /dev/null ++++ b/support/test-driver.h +@@ -0,0 +1,74 @@ ++/* Interfaces for the test driver. ++ 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 ++ . */ ++ ++#ifndef SUPPORT_TEST_DRIVER_H ++#define SUPPORT_TEST_DRIVER_H ++ ++#include ++ ++__BEGIN_DECLS ++ ++struct test_config ++{ ++ void (*prepare_function) (int argc, char **argv); ++ int (*test_function) (void); ++ int (*test_function_argv) (int argc, char **argv); ++ void (*cleanup_function) (void); ++ void (*cmdline_function) (int); ++ const void *options; /* Custom options if not NULL. */ ++ int timeout; /* Test timeout in seconds. */ ++ int expected_status; /* Expected exit status. */ ++ int expected_signal; /* If non-zero, expect termination by signal. */ ++ char no_mallopt; /* Boolean flag to disable mallopt. */ ++}; ++ ++enum ++ { ++ /* Test exit status which indicates that the feature is ++ unsupported. */ ++ EXIT_UNSUPPORTED = 77, ++ ++ /* Default timeout is twenty seconds. Tests should normally ++ complete faster than this, but if they don't, that's abnormal ++ (a bug) anyways. */ ++ DEFAULT_TIMEOUT = 20, ++ ++ /* Used for command line argument parsing. */ ++ OPT_DIRECT = 1000, ++ OPT_TESTDIR, ++ }; ++ ++/* Options provided by the test driver. */ ++#define TEST_DEFAULT_OPTIONS \ ++ { "verbose", no_argument, NULL, 'v' }, \ ++ { "direct", no_argument, NULL, OPT_DIRECT }, \ ++ { "test-dir", required_argument, NULL, OPT_TESTDIR }, \ ++ ++/* The directory the test should use for temporary files. */ ++extern const char *test_dir; ++ ++/* The number of --verbose arguments specified during program ++ invocation. This variable can be used to control the verbosity of ++ tests. */ ++extern unsigned int test_verbose; ++ ++int support_test_main (int argc, char **argv, const struct test_config *); ++ ++__END_DECLS ++ ++#endif /* SUPPORT_TEST_DRIVER_H */ +diff --git a/support/tst-support-namespace.c b/support/tst-support-namespace.c +new file mode 100644 +index 0000000000..a50b074f5e +--- /dev/null ++++ b/support/tst-support-namespace.c +@@ -0,0 +1,34 @@ ++/* Test entering namespaces. ++ 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 ++ ++static int ++do_test (void) ++{ ++ if (support_become_root ()) ++ printf ("info: acquired root-like privileges\n"); ++ if (support_enter_network_namespace ()) ++ printf ("info: entered network namespace\n"); ++ if (support_in_uts_namespace ()) ++ printf ("info: also entered UTS namespace\n"); ++ return 0; ++} ++ ++#include +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 +new file mode 100644 +index 0000000000..2c9372cc29 +--- /dev/null ++++ b/support/tst-support_record_failure-2.sh +@@ -0,0 +1,69 @@ ++#!/bin/sh ++# Test failure recording (with and without --direct). ++# 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 ++# . */ ++ ++set -e ++ ++common_objpfx=$1; shift ++test_program_prefix_before_env=$1; shift ++run_program_env=$1; shift ++test_program_prefix_after_env=$1; shift ++ ++run_test () { ++ expected_status="$1" ++ expected_output="$2" ++ shift 2 ++ args="${common_objpfx}support/tst-support_record_failure $*" ++ echo "running: $args" ++ set +e ++ output="$(${test_program_prefix_before_env} \ ++ ${run_program} ${test_program_prefix_after_env} $args)" ++ status=$? ++ set -e ++ echo " exit status: $status" ++ if test "$output" != "$expected_output" ; then ++ echo "error: unexpected output: $output" ++ exit 1 ++ fi ++ if test "$status" -ne "$expected_status" ; then ++ echo "error: exit status $expected_status expected" ++ exit 1 ++ fi ++} ++ ++different_status () { ++ direct="$1" ++ run_test 1 "error: 1 test failures" $direct --status=0 ++ 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:109: not true: false ++error: 1 test failures" $direct --test-verify ++ 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 ++} ++ ++different_status ++different_status --direct ++ ++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:116: not true: false" \ ++ --direct --test-verify-exit +diff --git a/support/tst-support_record_failure.c b/support/tst-support_record_failure.c +new file mode 100644 +index 0000000000..e739e739c3 +--- /dev/null ++++ b/support/tst-support_record_failure.c +@@ -0,0 +1,153 @@ ++/* Test support_record_failure state sharing. ++ 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 ++ ++static int exit_status_with_failure = -1; ++static bool test_verify; ++static bool test_verify_exit; ++enum ++ { ++ OPT_STATUS = 10001, ++ OPT_TEST_VERIFY, ++ OPT_TEST_VERIFY_EXIT, ++ }; ++#define CMDLINE_OPTIONS \ ++ { "status", required_argument, NULL, OPT_STATUS }, \ ++ { "test-verify", no_argument, NULL, OPT_TEST_VERIFY }, \ ++ { "test-verify-exit", no_argument, NULL, OPT_TEST_VERIFY_EXIT }, ++static void ++cmdline_process (int c) ++{ ++ switch (c) ++ { ++ case OPT_STATUS: ++ exit_status_with_failure = atoi (optarg); ++ break; ++ case OPT_TEST_VERIFY: ++ test_verify = true; ++ break; ++ case OPT_TEST_VERIFY_EXIT: ++ test_verify_exit = true; ++ break; ++ } ++} ++#define CMDLINE_PROCESS cmdline_process ++ ++static void ++check_failure_reporting (int phase, int zero, int unsupported) ++{ ++ int status = support_report_failure (0); ++ if (status != zero) ++ { ++ printf ("real-error (phase %d): support_report_failure (0) == %d\n", ++ phase, status); ++ exit (1); ++ } ++ status = support_report_failure (1); ++ if (status != 1) ++ { ++ printf ("real-error (phase %d): support_report_failure (1) == %d\n", ++ phase, status); ++ exit (1); ++ } ++ status = support_report_failure (2); ++ if (status != 2) ++ { ++ printf ("real-error (phase %d): support_report_failure (2) == %d\n", ++ phase, status); ++ exit (1); ++ } ++ status = support_report_failure (EXIT_UNSUPPORTED); ++ if (status != unsupported) ++ { ++ printf ("real-error (phase %d): " ++ "support_report_failure (EXIT_UNSUPPORTED) == %d\n", ++ phase, status); ++ exit (1); ++ } ++} ++ ++static int ++do_test (void) ++{ ++ if (exit_status_with_failure >= 0) ++ { ++ /* External invocation with requested error status. Used by ++ tst-support_report_failure-2.sh. */ ++ support_record_failure (); ++ return exit_status_with_failure; ++ } ++ TEST_VERIFY (true); ++ TEST_VERIFY_EXIT (true); ++ if (test_verify) ++ { ++ TEST_VERIFY (false); ++ if (test_verbose) ++ printf ("info: execution passed failed TEST_VERIFY\n"); ++ return 2; /* Expected exit status. */ ++ } ++ if (test_verify_exit) ++ { ++ TEST_VERIFY_EXIT (false); ++ return 3; /* Not reached. Expected exit status is 1. */ ++ } ++ ++ printf ("info: This test tests the test framework.\n" ++ "info: It reports some expected errors on stdout.\n"); ++ ++ /* Check that the status is passed through unchanged. */ ++ check_failure_reporting (1, 0, EXIT_UNSUPPORTED); ++ ++ /* Check state propagation from a subprocess. */ ++ pid_t pid = xfork (); ++ if (pid == 0) ++ { ++ support_record_failure (); ++ _exit (0); ++ } ++ int status; ++ xwaitpid (pid, &status, 0); ++ if (status != 0) ++ { ++ printf ("real-error: incorrect status from subprocess: %d\n", status); ++ return 1; ++ } ++ check_failure_reporting (2, 1, 1); ++ ++ /* Also test directly in the parent process. */ ++ support_record_failure_reset (); ++ check_failure_reporting (3, 0, EXIT_UNSUPPORTED); ++ support_record_failure (); ++ check_failure_reporting (4, 1, 1); ++ ++ /* We need to mask the failure above. */ ++ support_record_failure_reset (); ++ return 0; ++} ++ ++#include +diff --git a/sysdeps/unix/sysv/linux/sh/pwrite64.c b/support/write_message.c +similarity index 68% +rename from sysdeps/unix/sysv/linux/sh/pwrite64.c +rename to support/write_message.c +index 683a5d9886..f03ed931d6 100644 +--- a/sysdeps/unix/sysv/linux/sh/pwrite64.c ++++ b/support/write_message.c +@@ -1,6 +1,6 @@ +-/* Copyright (C) 1997-2016 Free Software Foundation, Inc. ++/* Write a message to standard output. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. +- Contributed by Ralf Baechle , 1998. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public +@@ -16,8 +16,14 @@ + License along with the GNU C Library; if not, see + . */ + +-/* SH4 ABI does not really require argument alignment for 64-bits, but +- the kernel interface for pread adds a dummy long argument before the +- offset. */ +-#define __ALIGNMENT_ARG +-#include ++#include ++ ++#include ++#include ++ ++void ++write_message (const char *message) ++{ ++ ssize_t unused __attribute__ ((unused)); ++ unused = write (STDOUT_FILENO, message, strlen (message)); ++} +diff --git a/support/xaccept.c b/support/xaccept.c +new file mode 100644 +index 0000000000..7b25af3b05 +--- /dev/null ++++ b/support/xaccept.c +@@ -0,0 +1,32 @@ ++/* accept with error checking. ++ 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 ++ ++int ++xaccept (int fd, struct sockaddr *sa, socklen_t *salen) ++{ ++ int clientfd = accept (fd, sa, salen); ++ if (clientfd < 0) ++ FAIL_EXIT1 ("accept (%d): %m", fd); ++ return clientfd; ++} +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/xasprintf.c b/support/xasprintf.c +new file mode 100644 +index 0000000000..5157680fa2 +--- /dev/null ++++ b/support/xasprintf.c +@@ -0,0 +1,36 @@ ++/* Error-checking wrapper for asprintf. ++ 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 ++ ++char * ++xasprintf (const char *format, ...) ++{ ++ va_list ap; ++ va_start (ap, format); ++ char *result; ++ if (vasprintf (&result, format, ap) < 0) ++ FAIL_EXIT1 ("asprintf: %m"); ++ va_end (ap); ++ return result; ++} +diff --git a/support/xbind.c b/support/xbind.c +new file mode 100644 +index 0000000000..cfc6dd8fa8 +--- /dev/null ++++ b/support/xbind.c +@@ -0,0 +1,30 @@ ++/* bind with error checking. ++ 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 ++ ++void ++xbind (int fd, const struct sockaddr *sa, socklen_t sa_len) ++{ ++ if (bind (fd, sa, sa_len) != 0) ++ FAIL_EXIT1 ("bind (%d), family %d: %m", fd, sa->sa_family); ++} +diff --git a/sysdeps/unix/sysv/linux/sh/pread64.c b/support/xcalloc.c +similarity index 67% +rename from sysdeps/unix/sysv/linux/sh/pread64.c +rename to support/xcalloc.c +index b2e8a25788..135f42dab2 100644 +--- a/sysdeps/unix/sysv/linux/sh/pread64.c ++++ b/support/xcalloc.c +@@ -1,6 +1,6 @@ +-/* Copyright (C) 1997-2016 Free Software Foundation, Inc. ++/* Error-checking wrapper for calloc. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. +- Contributed by Ulrich Drepper , 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public +@@ -16,8 +16,19 @@ + License along with the GNU C Library; if not, see + . */ + +-/* SH4 ABI does not really require argument alignment for 64-bits, but +- the kernel interface for pread adds a dummy long argument before the +- offset. */ +-#define __ALIGNMENT_ARG +-#include ++#include ++ ++#include ++#include ++#include ++ ++void * ++xcalloc (size_t n, size_t s) ++{ ++ void *p; ++ ++ p = calloc (n, s); ++ if (p == NULL) ++ oom_error ("calloc", n * s); ++ return p; ++} +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/xconnect.c b/support/xconnect.c +new file mode 100644 +index 0000000000..0266dbc643 +--- /dev/null ++++ b/support/xconnect.c +@@ -0,0 +1,30 @@ ++/* connect with error checking. ++ 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 ++ ++void ++xconnect (int fd, const struct sockaddr *sa, socklen_t sa_len) ++{ ++ if (connect (fd, sa, sa_len) != 0) ++ FAIL_EXIT1 ("connect (%d), family %d: %m", fd, sa->sa_family); ++} +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/xfclose.c b/support/xfclose.c +new file mode 100644 +index 0000000000..2737f05044 +--- /dev/null ++++ b/support/xfclose.c +@@ -0,0 +1,33 @@ ++/* fclose with error checking. ++ 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 ++ ++void ++xfclose (FILE *fp) ++{ ++ if (ferror (fp)) ++ FAIL_EXIT1 ("stdio stream closed with pending errors"); ++ if (fflush (fp) != 0) ++ FAIL_EXIT1 ("fflush: %m"); ++ if (fclose (fp) != 0) ++ FAIL_EXIT1 ("fclose: %m"); ++} +diff --git a/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdimf-vis3.S b/support/xfopen.c +similarity index 67% +rename from sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdimf-vis3.S +rename to support/xfopen.c +index 081fc15b62..14532a09f3 100644 +--- a/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdimf-vis3.S ++++ b/support/xfopen.c +@@ -1,7 +1,6 @@ +-/* Compute positive difference, sparc 32-bit+v9+vis3. +- Copyright (C) 2013-2016 Free Software Foundation, Inc. ++/* fopen with error checking. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. +- Contributed by David S. Miller . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public +@@ -17,16 +16,16 @@ + License along with the GNU C Library; if not, see + . */ + +-#include ++#include + +-ENTRY(__fdimf_vis3) +- movwtos %o0, %f0 +- movwtos %o1, %f1 +- fcmps %f0, %f1 +- fbug 1f +- nop +- fzeros %f0 +- fnegs %f0, %f1 +-1: retl +- fsubs %f0, %f1, %f0 +-END(__fdimf_vis3) ++#include ++#include ++ ++FILE * ++xfopen (const char *path, const char *mode) ++{ ++ FILE *fp = fopen (path, mode); ++ if (fp == NULL) ++ FAIL_EXIT1 ("could not open %s (mode \"%s\"): %m", path, mode); ++ return fp; ++} +diff --git a/support/xfork.c b/support/xfork.c +new file mode 100644 +index 0000000000..aa52ba62c5 +--- /dev/null ++++ b/support/xfork.c +@@ -0,0 +1,32 @@ ++/* fork with error checking. ++ 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 ++ ++pid_t ++xfork (void) ++{ ++ pid_t result = fork (); ++ if (result < 0) ++ FAIL_EXIT1 ("fork: %m"); ++ return result; ++} +diff --git a/support/xgetsockname.c b/support/xgetsockname.c +new file mode 100644 +index 0000000000..c3bd884f8d +--- /dev/null ++++ b/support/xgetsockname.c +@@ -0,0 +1,30 @@ ++/* getsockname with error checking. ++ 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 ++ ++void ++xgetsockname (int fd, struct sockaddr *sa, socklen_t *plen) ++{ ++ if (getsockname (fd, sa, plen) != 0) ++ FAIL_EXIT1 ("setsockopt (%d): %m", fd); ++} +diff --git a/support/xlisten.c b/support/xlisten.c +new file mode 100644 +index 0000000000..1953e5900a +--- /dev/null ++++ b/support/xlisten.c +@@ -0,0 +1,30 @@ ++/* listen with error checking. ++ 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 ++ ++void ++xlisten (int fd, int backlog) ++{ ++ if (listen (fd, backlog) != 0) ++ FAIL_EXIT1 ("listen (%d, %d): %m", fd, backlog); ++} +diff --git a/support/xmalloc.c b/support/xmalloc.c +new file mode 100644 +index 0000000000..450f699789 +--- /dev/null ++++ b/support/xmalloc.c +@@ -0,0 +1,34 @@ ++/* Error-checking wrapper for malloc. ++ 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 ++ ++void * ++xmalloc (size_t n) ++{ ++ void *p; ++ ++ p = malloc (n); ++ if (p == NULL) ++ oom_error ("malloc", n); ++ return p; ++} +diff --git a/sysdeps/sparc/sparc32/fpu/s_fdim.S b/support/xmemstream.c +similarity index 54% +rename from sysdeps/sparc/sparc32/fpu/s_fdim.S +rename to support/xmemstream.c +index e93970faae..bce6dc9170 100644 +--- a/sysdeps/sparc/sparc32/fpu/s_fdim.S ++++ b/support/xmemstream.c +@@ -1,7 +1,6 @@ +-/* Compute positive difference, sparc 32-bit. +- Copyright (C) 2013-2016 Free Software Foundation, Inc. ++/* Error-checking wrappers for memstream functions. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. +- Contributed by David S. Miller . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public +@@ -17,26 +16,27 @@ + License along with the GNU C Library; if not, see + . */ + +-#include +-#include ++#include + +-ENTRY(__fdim) +- std %o0, [%sp + 72] +- std %o2, [%sp + 80] +- ldd [%sp + 72], %f0 +- ldd [%sp + 80], %f2 +- fcmpd %f0, %f2 +- st %g0, [%sp + 72] +- fbug 1f +- st %g0, [%sp + 76] +- ldd [%sp + 72], %f0 +- fnegs %f0, %f2 +- fmovs %f1, %f3 +-1: retl +- fsubd %f0, %f2, %f0 +-END(__fdim) +-weak_alias (__fdim, fdim) ++#include ++#include ++#include ++#include + +-#if LONG_DOUBLE_COMPAT(libm, GLIBC_2_1) +-compat_symbol (libm, __fdim, fdiml, GLIBC_2_1); +-#endif ++void ++xopen_memstream (struct xmemstream *stream) ++{ ++ int old_errno = errno; ++ *stream = (struct xmemstream) {}; ++ stream->out = open_memstream (&stream->buffer, &stream->length); ++ if (stream->out == NULL) ++ FAIL_EXIT1 ("open_memstream: %m"); ++ errno = old_errno; ++} ++ ++void ++xfclose_memstream (struct xmemstream *stream) ++{ ++ xfclose (stream->out); ++ stream->out = NULL; ++} +diff --git a/support/xmemstream.h b/support/xmemstream.h +new file mode 100644 +index 0000000000..e5ba231e4d +--- /dev/null ++++ b/support/xmemstream.h +@@ -0,0 +1,49 @@ ++/* Error-checking wrappers for memstream functions. ++ 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 ++ . */ ++ ++#ifndef SUPPORT_XMEMSTREAM_H ++#define SUPPORT_XMEMSTREAM_H ++ ++#include ++#include ++ ++__BEGIN_DECLS ++ ++/* Wrappers for other libc functions. */ ++struct xmemstream ++{ ++ FILE *out; ++ char *buffer; ++ size_t length; ++}; ++ ++/* Create a new in-memory stream. Initializes *STREAM. After this ++ function returns, STREAM->out is a file descriptor open for ++ writing. errno is preserved, so that the %m format specifier can ++ be used for writing to STREAM->out. */ ++void xopen_memstream (struct xmemstream *stream); ++ ++/* Closes STREAM->OUT. After this function returns, STREAM->buffer ++ and STREAM->length denote a memory range which contains the bytes ++ written to the output stream. The caller should free ++ STREAM->buffer. */ ++void xfclose_memstream (struct xmemstream *stream); ++ ++__END_DECLS ++ ++#endif /* SUPPORT_XMEMSTREAM_H */ +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/xmmap.c b/support/xmmap.c +new file mode 100644 +index 0000000000..435b1eb733 +--- /dev/null ++++ b/support/xmmap.c +@@ -0,0 +1,31 @@ ++/* mmap with error checking. ++ 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 ++ ++void * ++xmmap (void *addr, size_t length, int prot, int flags, int fd) ++{ ++ void *result = mmap (addr, length, prot, flags, fd, 0); ++ if (result == MAP_FAILED) ++ FAIL_EXIT1 ("mmap of %zu bytes, prot=0x%x, flags=0x%x: %m", ++ length, prot, flags); ++ return result; ++} +diff --git a/support/xmunmap.c b/support/xmunmap.c +new file mode 100644 +index 0000000000..6ef5a4a468 +--- /dev/null ++++ b/support/xmunmap.c +@@ -0,0 +1,28 @@ ++/* munmap with error checking. ++ 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 ++ ++void ++xmunmap (void *addr, size_t length) ++{ ++ if (munmap (addr, length) != 0) ++ FAIL_EXIT1 ("munmap of %zu bytes: %m", length); ++} +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/xpoll.c b/support/xpoll.c +new file mode 100644 +index 0000000000..bec2521ffc +--- /dev/null ++++ b/support/xpoll.c +@@ -0,0 +1,32 @@ ++/* poll with error checking. ++ 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 ++ ++int ++xpoll (struct pollfd *fds, nfds_t nfds, int timeout) ++{ ++ int ret = poll (fds, nfds, timeout); ++ if (ret < 0) ++ FAIL_EXIT1 ("poll: %m"); ++ return ret; ++} +diff --git a/support/xpthread_attr_destroy.c b/support/xpthread_attr_destroy.c +new file mode 100644 +index 0000000000..664c809e9f +--- /dev/null ++++ b/support/xpthread_attr_destroy.c +@@ -0,0 +1,26 @@ ++/* pthread_attr_destroy 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_destroy (pthread_attr_t *attr) ++{ ++ xpthread_check_return ("pthread_attr_destroy", ++ pthread_attr_destroy (attr)); ++} +diff --git a/support/xpthread_attr_init.c b/support/xpthread_attr_init.c +new file mode 100644 +index 0000000000..2e30ade9ab +--- /dev/null ++++ b/support/xpthread_attr_init.c +@@ -0,0 +1,25 @@ ++/* pthread_attr_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_attr_init (pthread_attr_t *attr) ++{ ++ xpthread_check_return ("pthread_attr_init", pthread_attr_init (attr)); ++} +diff --git a/support/xpthread_attr_setdetachstate.c b/support/xpthread_attr_setdetachstate.c +new file mode 100644 +index 0000000000..b544dbaa42 +--- /dev/null ++++ b/support/xpthread_attr_setdetachstate.c +@@ -0,0 +1,27 @@ ++/* pthread_attr_setdetachstate 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_setdetachstate (pthread_attr_t *attr, int detachstate) ++{ ++ xpthread_check_return ("pthread_attr_setdetachstate", ++ pthread_attr_setdetachstate (attr, ++ detachstate)); ++} +diff --git a/support/xpthread_attr_setstacksize.c b/support/xpthread_attr_setstacksize.c +new file mode 100644 +index 0000000000..02d06310a9 +--- /dev/null ++++ b/support/xpthread_attr_setstacksize.c +@@ -0,0 +1,26 @@ ++/* pthread_attr_setstacksize 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_setstacksize (pthread_attr_t *attr, size_t stacksize) ++{ ++ xpthread_check_return ("pthread_attr_setstacksize", ++ pthread_attr_setstacksize (attr, stacksize)); ++} +diff --git a/support/xpthread_barrier_destroy.c b/support/xpthread_barrier_destroy.c +new file mode 100644 +index 0000000000..efc0719a63 +--- /dev/null ++++ b/support/xpthread_barrier_destroy.c +@@ -0,0 +1,26 @@ ++/* pthread_barrier_destroy with error checking. ++ 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 ++ ++void ++xpthread_barrier_destroy (pthread_barrier_t *barrier) ++{ ++ xpthread_check_return ("pthread_barrier_destroy", ++ pthread_barrier_destroy (barrier)); ++} +diff --git a/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdim-vis3.S b/support/xpthread_barrier_init.c +similarity index 65% +rename from sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdim-vis3.S +rename to support/xpthread_barrier_init.c +index 4a479b1a59..b32dad1315 100644 +--- a/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdim-vis3.S ++++ b/support/xpthread_barrier_init.c +@@ -1,7 +1,6 @@ +-/* Compute positive difference, sparc 32-bit+v9+vis3. +- Copyright (C) 2013-2016 Free Software Foundation, Inc. ++/* pthread_barrier_init with error checking. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. +- Contributed by David S. Miller . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public +@@ -17,18 +16,12 @@ + License along with the GNU C Library; if not, see + . */ + +-#include ++#include + +-ENTRY(__fdim_vis3) +- movwtos %o0, %f0 +- movwtos %o1, %f1 +- movwtos %o2, %f2 +- movwtos %o3, %f3 +- fcmpd %f0, %f2 +- fbug 1f +- nop +- fzero %f0 +- fnegd %f0, %f2 +-1: retl +- fsubd %f0, %f2, %f0 +-END(__fdim_vis3) ++void ++xpthread_barrier_init (pthread_barrier_t *barrier, ++ pthread_barrierattr_t *attr, unsigned int count) ++{ ++ xpthread_check_return ("pthread_barrier_init", ++ pthread_barrier_init (barrier, attr, count)); ++} +diff --git a/support/xpthread_barrier_wait.c b/support/xpthread_barrier_wait.c +new file mode 100644 +index 0000000000..7cee44d0a3 +--- /dev/null ++++ b/support/xpthread_barrier_wait.c +@@ -0,0 +1,28 @@ ++/* pthread_barrier_wait with error checking. ++ 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 ++ ++int ++xpthread_barrier_wait (pthread_barrier_t *barrier) ++{ ++ int ret = pthread_barrier_wait (barrier); ++ if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD) ++ xpthread_check_return ("pthread_barrier_wait", ret); ++ return ret == PTHREAD_BARRIER_SERIAL_THREAD; ++} +diff --git a/support/xpthread_cancel.c b/support/xpthread_cancel.c +new file mode 100644 +index 0000000000..3af16f9b54 +--- /dev/null ++++ b/support/xpthread_cancel.c +@@ -0,0 +1,25 @@ ++/* pthread_cancel with error checking. ++ 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 ++ ++void ++xpthread_cancel (pthread_t thr) ++{ ++ xpthread_check_return ("pthread_cancel", pthread_cancel (thr)); ++} +diff --git a/support/xpthread_check_return.c b/support/xpthread_check_return.c +new file mode 100644 +index 0000000000..3094d82e9c +--- /dev/null ++++ b/support/xpthread_check_return.c +@@ -0,0 +1,34 @@ ++/* Return value checking for pthread functions, exit variant. ++ 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 ++ ++void ++xpthread_check_return (const char *function, int value) ++{ ++ if (value != 0) ++ { ++ errno = value; ++ FAIL_EXIT1 ("%s: %m", function); ++ } ++} +diff --git a/support/xpthread_cond_wait.c b/support/xpthread_cond_wait.c +new file mode 100644 +index 0000000000..b0e9b2a232 +--- /dev/null ++++ b/support/xpthread_cond_wait.c +@@ -0,0 +1,26 @@ ++/* pthread_cond_wait with error checking. ++ 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 ++ ++void ++xpthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex) ++{ ++ xpthread_check_return ++ ("pthread_cond_wait", pthread_cond_wait (cond, mutex)); ++} +diff --git a/support/xpthread_create.c b/support/xpthread_create.c +new file mode 100644 +index 0000000000..98c63e54c3 +--- /dev/null ++++ b/support/xpthread_create.c +@@ -0,0 +1,29 @@ ++/* pthread_create with error checking. ++ 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 ++ ++pthread_t ++xpthread_create (pthread_attr_t *attr, ++ void *(*thread_func) (void *), void *closure) ++{ ++ pthread_t thr; ++ xpthread_check_return ++ ("pthread_create", pthread_create (&thr, attr, thread_func, closure)); ++ return thr; ++} +diff --git a/support/xpthread_detach.c b/support/xpthread_detach.c +new file mode 100644 +index 0000000000..2088af2f57 +--- /dev/null ++++ b/support/xpthread_detach.c +@@ -0,0 +1,25 @@ ++/* pthread_detach with error checking. ++ 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 ++ ++void ++xpthread_detach (pthread_t thr) ++{ ++ xpthread_check_return ("pthread_detach", pthread_detach (thr)); ++} +diff --git a/support/xpthread_join.c b/support/xpthread_join.c +new file mode 100644 +index 0000000000..f23bb9a5ae +--- /dev/null ++++ b/support/xpthread_join.c +@@ -0,0 +1,27 @@ ++/* pthread_join with error checking. ++ 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 ++ ++void * ++xpthread_join (pthread_t thr) ++{ ++ void *result; ++ xpthread_check_return ("pthread_join", pthread_join (thr, &result)); ++ return result; ++} +diff --git a/support/xpthread_mutex_consistent.c b/support/xpthread_mutex_consistent.c +new file mode 100644 +index 0000000000..52364be365 +--- /dev/null ++++ b/support/xpthread_mutex_consistent.c +@@ -0,0 +1,26 @@ ++/* pthread_mutex_consistent with error checking. ++ 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 ++ ++void ++xpthread_mutex_consistent (pthread_mutex_t *mutex) ++{ ++ xpthread_check_return ("pthread_mutex_consistent", ++ pthread_mutex_consistent (mutex)); ++} +diff --git a/support/xpthread_mutex_destroy.c b/support/xpthread_mutex_destroy.c +new file mode 100644 +index 0000000000..f11f8f0acd +--- /dev/null ++++ b/support/xpthread_mutex_destroy.c +@@ -0,0 +1,26 @@ ++/* pthread_mutex_destroy with error checking. ++ 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 ++ ++void ++xpthread_mutex_destroy (pthread_mutex_t *mutex) ++{ ++ xpthread_check_return ("pthread_mutex_destroy", ++ pthread_mutex_destroy (mutex)); ++} +diff --git a/support/xpthread_mutex_init.c b/support/xpthread_mutex_init.c +new file mode 100644 +index 0000000000..2d16d1b9d9 +--- /dev/null ++++ b/support/xpthread_mutex_init.c +@@ -0,0 +1,26 @@ ++/* pthread_mutex_init with error checking. ++ 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 ++ ++void ++xpthread_mutex_init (pthread_mutex_t *mutex, const pthread_mutexattr_t *attr) ++{ ++ xpthread_check_return ("pthread_mutex_init", ++ pthread_mutex_init (mutex, attr)); ++} +diff --git a/support/xpthread_mutex_lock.c b/support/xpthread_mutex_lock.c +new file mode 100644 +index 0000000000..af727b45f3 +--- /dev/null ++++ b/support/xpthread_mutex_lock.c +@@ -0,0 +1,25 @@ ++/* pthread_mutex_lock with error checking. ++ 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 ++ ++void ++xpthread_mutex_lock (pthread_mutex_t *mutex) ++{ ++ xpthread_check_return ("pthread_mutex_lock", pthread_mutex_lock (mutex)); ++} +diff --git a/support/xpthread_mutex_unlock.c b/support/xpthread_mutex_unlock.c +new file mode 100644 +index 0000000000..161b41edf6 +--- /dev/null ++++ b/support/xpthread_mutex_unlock.c +@@ -0,0 +1,25 @@ ++/* pthread_mutex_unlock with error checking. ++ 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 ++ ++void ++xpthread_mutex_unlock (pthread_mutex_t *mutex) ++{ ++ xpthread_check_return ("pthread_mutex_unlock", pthread_mutex_unlock (mutex)); ++} +diff --git a/support/xpthread_mutexattr_destroy.c b/support/xpthread_mutexattr_destroy.c +new file mode 100644 +index 0000000000..c699e32b41 +--- /dev/null ++++ b/support/xpthread_mutexattr_destroy.c +@@ -0,0 +1,26 @@ ++/* pthread_mutexattr_destroy 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_mutexattr_destroy (pthread_mutexattr_t *attr) ++{ ++ xpthread_check_return ("pthread_mutexattr_destroy", ++ pthread_mutexattr_destroy (attr)); ++} +diff --git a/support/xpthread_mutexattr_init.c b/support/xpthread_mutexattr_init.c +new file mode 100644 +index 0000000000..fa93fab178 +--- /dev/null ++++ b/support/xpthread_mutexattr_init.c +@@ -0,0 +1,25 @@ ++/* pthread_mutexattr_init with error checking. ++ 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 ++ ++void ++xpthread_mutexattr_init (pthread_mutexattr_t *attr) ++{ ++ xpthread_check_return ("pthread_mutexattr_init", pthread_mutexattr_init (attr)); ++} +diff --git a/sysdeps/sparc/sparc64/fpu/s_fdim.S b/support/xpthread_mutexattr_setprotocol.c +similarity index 67% +rename from sysdeps/sparc/sparc64/fpu/s_fdim.S +rename to support/xpthread_mutexattr_setprotocol.c +index 7fae72a251..353f75e3d7 100644 +--- a/sysdeps/sparc/sparc64/fpu/s_fdim.S ++++ b/support/xpthread_mutexattr_setprotocol.c +@@ -1,7 +1,6 @@ +-/* Compute positive difference, sparc 64-bit. +- Copyright (C) 2013-2016 Free Software Foundation, Inc. ++/* pthread_mutexattr_setprotocol with error checking. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. +- Contributed by David S. Miller . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public +@@ -17,16 +16,11 @@ + License along with the GNU C Library; if not, see + . */ + +-#include +-#include ++#include + +-ENTRY(__fdim) +- fcmpd %f0, %f2 +- fbug 1f +- nop +- fzero %f0 +- fnegd %f0, %f2 +-1: retl +- fsubd %f0, %f2, %f0 +-END(__fdim) +-weak_alias (__fdim, fdim) ++void ++xpthread_mutexattr_setprotocol (pthread_mutexattr_t *attr, int flag) ++{ ++ xpthread_check_return ("pthread_mutexattr_setprotocol", ++ pthread_mutexattr_setprotocol (attr, flag)); ++} +diff --git a/support/xpthread_mutexattr_setpshared.c b/support/xpthread_mutexattr_setpshared.c +new file mode 100644 +index 0000000000..242da1aeca +--- /dev/null ++++ b/support/xpthread_mutexattr_setpshared.c +@@ -0,0 +1,26 @@ ++/* pthread_mutexattr_setpshared with error checking. ++ 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 ++ ++void ++xpthread_mutexattr_setpshared (pthread_mutexattr_t *attr, int flag) ++{ ++ xpthread_check_return ("pthread_mutexattr_setpshared", ++ pthread_mutexattr_setpshared (attr, flag)); ++} +diff --git a/support/xpthread_mutexattr_setrobust.c b/support/xpthread_mutexattr_setrobust.c +new file mode 100644 +index 0000000000..d7d6fa8630 +--- /dev/null ++++ b/support/xpthread_mutexattr_setrobust.c +@@ -0,0 +1,26 @@ ++/* pthread_mutexattr_setrobust with error checking. ++ 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 ++ ++void ++xpthread_mutexattr_setrobust (pthread_mutexattr_t *attr, int flag) ++{ ++ xpthread_check_return ("pthread_mutexattr_setrobust", ++ pthread_mutexattr_setrobust (attr, flag)); ++} +diff --git a/support/xpthread_mutexattr_settype.c b/support/xpthread_mutexattr_settype.c +new file mode 100644 +index 0000000000..cf22170b56 +--- /dev/null ++++ b/support/xpthread_mutexattr_settype.c +@@ -0,0 +1,26 @@ ++/* pthread_mutexattr_settype with error checking. ++ 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 ++ ++void ++xpthread_mutexattr_settype (pthread_mutexattr_t *attr, int flag) ++{ ++ xpthread_check_return ("pthread_mutexattr_settype", ++ pthread_mutexattr_settype (attr, flag)); ++} +diff --git a/support/xpthread_once.c b/support/xpthread_once.c +new file mode 100644 +index 0000000000..70d58dbab2 +--- /dev/null ++++ b/support/xpthread_once.c +@@ -0,0 +1,25 @@ ++/* pthread_once with error checking. ++ 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 ++ ++void ++xpthread_once (pthread_once_t *guard, void (*func) (void)) ++{ ++ xpthread_check_return ("pthread_once", pthread_once (guard, func)); ++} +diff --git a/support/xpthread_sigmask.c b/support/xpthread_sigmask.c +new file mode 100644 +index 0000000000..0ba9ca02dc +--- /dev/null ++++ b/support/xpthread_sigmask.c +@@ -0,0 +1,34 @@ ++/* pthread_sigmask with error checking. ++ 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 ++ ++void ++xpthread_sigmask (int how, const sigset_t *set, sigset_t *oldset) ++{ ++ if (pthread_sigmask (how, set, oldset) != 0) ++ { ++ write_message ("error: pthread_setmask failed\n"); ++ /* Do not use exit because pthread_sigmask can be called from a ++ signal handler. */ ++ _exit (1); ++ } ++} +diff --git a/support/xpthread_spin_lock.c b/support/xpthread_spin_lock.c +new file mode 100644 +index 0000000000..6975215b17 +--- /dev/null ++++ b/support/xpthread_spin_lock.c +@@ -0,0 +1,25 @@ ++/* pthread_spin_lock with error checking. ++ 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 ++ ++void ++xpthread_spin_lock (pthread_spinlock_t *lock) ++{ ++ xpthread_check_return ("pthread_spin_lock", pthread_spin_lock (lock)); ++} +diff --git a/support/xpthread_spin_unlock.c b/support/xpthread_spin_unlock.c +new file mode 100644 +index 0000000000..4f19a44c48 +--- /dev/null ++++ b/support/xpthread_spin_unlock.c +@@ -0,0 +1,25 @@ ++/* pthread_spin_unlock with error checking. ++ 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 ++ ++void ++xpthread_spin_unlock (pthread_spinlock_t *lock) ++{ ++ xpthread_check_return ("pthread_spin_unlock", pthread_spin_unlock (lock)); ++} +diff --git a/support/xrealloc.c b/support/xrealloc.c +new file mode 100644 +index 0000000000..00c313880c +--- /dev/null ++++ b/support/xrealloc.c +@@ -0,0 +1,32 @@ ++/* Error-checking wrapper for realloc. ++ 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 ++ ++void * ++xrealloc (void *p, size_t n) ++{ ++ void *result = realloc (p, n); ++ if (result == NULL && (n > 0 || p == NULL)) ++ oom_error ("realloc", n); ++ return result; ++} +diff --git a/support/xrecvfrom.c b/support/xrecvfrom.c +new file mode 100644 +index 0000000000..17809c4dd2 +--- /dev/null ++++ b/support/xrecvfrom.c +@@ -0,0 +1,33 @@ ++/* recvfrom with error checking. ++ 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 ++ ++size_t ++xrecvfrom (int fd, void *buf, size_t buflen, int flags, ++ struct sockaddr *sa, socklen_t *salen) ++{ ++ ssize_t ret = recvfrom (fd, buf, buflen, flags, sa, salen); ++ if (ret < 0) ++ FAIL_EXIT1 ("error: recvfrom (%d), %zu bytes buffer: %m", fd, buflen); ++ return ret; ++} +diff --git a/support/xsendto.c b/support/xsendto.c +new file mode 100644 +index 0000000000..20bddf6965 +--- /dev/null ++++ b/support/xsendto.c +@@ -0,0 +1,35 @@ ++/* sendto with error checking. ++ 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 ++ ++void ++xsendto (int fd, const void *buf, size_t buflen, int flags, ++ const struct sockaddr *sa, socklen_t salen) ++{ ++ ssize_t ret = sendto (fd, buf, buflen, flags, sa, salen); ++ if (ret < 0) ++ FAIL_EXIT1 ("sendto (%d), %zu bytes, family %d: %m", ++ fd, buflen, sa->sa_family); ++ if (ret != buflen) ++ FAIL_EXIT1 ("sendto (%d) sent %zd bytes instead of %zu", fd, ret, buflen); ++} +diff --git a/sysdeps/sparc/sparc32/fpu/s_fdimf.S b/support/xsetsockopt.c +similarity index 62% +rename from sysdeps/sparc/sparc32/fpu/s_fdimf.S +rename to support/xsetsockopt.c +index c3fe8afa98..9931882e75 100644 +--- a/sysdeps/sparc/sparc32/fpu/s_fdimf.S ++++ b/support/xsetsockopt.c +@@ -1,7 +1,6 @@ +-/* Compute positive difference, sparc 32-bit. +- Copyright (C) 2013-2016 Free Software Foundation, Inc. ++/* setsockopt with error checking. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. +- Contributed by David S. Miller . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public +@@ -17,19 +16,16 @@ + License along with the GNU C Library; if not, see + . */ + +-#include ++#include + +-ENTRY(__fdimf) +- st %o0, [%sp + 72] +- st %o1, [%sp + 76] +- ld [%sp + 72], %f0 +- ld [%sp + 76], %f1 +- fcmps %f0, %f1 +- fbug 1f +- st %g0, [%sp + 72] +- ld [%sp + 72], %f0 +- fnegs %f0, %f1 +-1: retl +- fsubs %f0, %f1, %f0 +-END(__fdimf) +-weak_alias (__fdimf, fdimf) ++#include ++#include ++#include ++ ++void ++xsetsockopt (int fd, int level, int name, const void *val, socklen_t vallen) ++{ ++ if (setsockopt (fd, level, name, val, vallen) != 0) ++ FAIL_EXIT1 ("setsockopt (%d, %d, %d), %zu bytes: %m", ++ fd, level, name, (size_t) vallen); ++} +diff --git a/support/xsignal.h b/support/xsignal.h +new file mode 100644 +index 0000000000..3dc0d9d5ce +--- /dev/null ++++ b/support/xsignal.h +@@ -0,0 +1,34 @@ ++/* Support functionality for using signals. ++ 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 ++ . */ ++ ++#ifndef SUPPORT_SIGNAL_H ++#define SUPPORT_SIGNAL_H ++ ++#include ++#include ++ ++__BEGIN_DECLS ++ ++/* The following functions call the corresponding libpthread functions ++ and terminate the process on error. */ ++ ++void xpthread_sigmask (int how, const sigset_t *set, sigset_t *oldset); ++ ++__END_DECLS ++ ++#endif /* SUPPORT_SIGNAL_H */ +diff --git a/support/xsocket.c b/support/xsocket.c +new file mode 100644 +index 0000000000..c1deaee924 +--- /dev/null ++++ b/support/xsocket.c +@@ -0,0 +1,32 @@ ++/* socket with error checking. ++ 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 ++ ++int ++xsocket (int domain, int type, int protocol) ++{ ++ int fd = socket (domain, type, protocol); ++ if (fd < 0) ++ FAIL_EXIT1 ("socket (%d, %d, %d): %m\n", domain, type, protocol); ++ return fd; ++} +diff --git a/support/xsocket.h b/support/xsocket.h +new file mode 100644 +index 0000000000..d6724948d8 +--- /dev/null ++++ b/support/xsocket.h +@@ -0,0 +1,39 @@ ++/* Error-checking wrappers for socket functions. ++ 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 ++ . */ ++ ++#ifndef SUPPORT_XSOCKET_H ++#define SUPPORT_XSOCKET_H ++ ++#include ++#include ++#include ++ ++int xsocket (int, int, int); ++void xsetsockopt (int, int, int, const void *, socklen_t); ++void xgetsockname (int, struct sockaddr *, socklen_t *); ++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 *); ++int xpoll (struct pollfd *, nfds_t, int); ++ ++#endif /* SUPPORT_XSOCKET_H */ +diff --git a/support/xstdio.h b/support/xstdio.h +new file mode 100644 +index 0000000000..bcc2e863bf +--- /dev/null ++++ b/support/xstdio.h +@@ -0,0 +1,32 @@ ++/* Error-checking wrappers for stdio functions. ++ 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 ++ . */ ++ ++#ifndef SUPPORT_XSTDIO_H ++#define SUPPORT_XSTDIO_H ++ ++#include ++#include ++ ++__BEGIN_DECLS ++ ++FILE *xfopen (const char *path, const char *mode); ++void xfclose (FILE *); ++ ++__END_DECLS ++ ++#endif /* SUPPORT_XSTDIO_H */ +diff --git a/support/xstrdup.c b/support/xstrdup.c +new file mode 100644 +index 0000000000..d6a8c04baf +--- /dev/null ++++ b/support/xstrdup.c +@@ -0,0 +1,30 @@ ++/* strdup with error checking. ++ 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 ++ ++char * ++xstrdup (const char *s) ++{ ++ char *p = strdup (s); ++ if (p == NULL) ++ oom_error ("strdup", strlen (s)); ++ return p; ++} +diff --git a/support/xthread.h b/support/xthread.h +new file mode 100644 +index 0000000000..6dd7e709be +--- /dev/null ++++ b/support/xthread.h +@@ -0,0 +1,77 @@ ++/* Support functionality for using threads. ++ 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 ++ . */ ++ ++#ifndef SUPPORT_THREAD_H ++#define SUPPORT_THREAD_H ++ ++#include ++#include ++ ++__BEGIN_DECLS ++ ++/* Terminate the process (with exit status 0) after SECONDS have ++ elapsed, from a helper thread. The process is terminated with the ++ exit function, so atexit handlers are executed. */ ++void delayed_exit (int seconds); ++ ++/* Terminate the process (with exit status 1) if VALUE is not zero. ++ In that case, print a failure message to standard output mentioning ++ FUNCTION. The process is terminated with the exit function, so ++ atexit handlers are executed. */ ++void xpthread_check_return (const char *function, int value); ++ ++/* The following functions call the corresponding libpthread functions ++ and terminate the process on error. */ ++ ++void xpthread_barrier_init (pthread_barrier_t *barrier, ++ pthread_barrierattr_t *attr, unsigned int count); ++void xpthread_barrier_destroy (pthread_barrier_t *barrier); ++void xpthread_mutexattr_destroy (pthread_mutexattr_t *); ++void xpthread_mutexattr_init (pthread_mutexattr_t *); ++void xpthread_mutexattr_setprotocol (pthread_mutexattr_t *, int); ++void xpthread_mutexattr_setpshared (pthread_mutexattr_t *, int); ++void xpthread_mutexattr_setrobust (pthread_mutexattr_t *, int); ++void xpthread_mutexattr_settype (pthread_mutexattr_t *, int); ++void xpthread_mutex_init (pthread_mutex_t *, const pthread_mutexattr_t *); ++void xpthread_mutex_destroy (pthread_mutex_t *); ++void xpthread_mutex_lock (pthread_mutex_t *mutex); ++void xpthread_mutex_unlock (pthread_mutex_t *mutex); ++void xpthread_mutex_consistent (pthread_mutex_t *); ++void xpthread_spin_lock (pthread_spinlock_t *lock); ++void xpthread_spin_unlock (pthread_spinlock_t *lock); ++void xpthread_cond_wait (pthread_cond_t * cond, pthread_mutex_t * mutex); ++pthread_t xpthread_create (pthread_attr_t *attr, ++ void *(*thread_func) (void *), void *closure); ++void xpthread_detach (pthread_t thr); ++void xpthread_cancel (pthread_t thr); ++void *xpthread_join (pthread_t thr); ++void xpthread_once (pthread_once_t *guard, void (*func) (void)); ++void xpthread_attr_destroy (pthread_attr_t *attr); ++void xpthread_attr_init (pthread_attr_t *attr); ++void xpthread_attr_setdetachstate (pthread_attr_t *attr, ++ int detachstate); ++void xpthread_attr_setstacksize (pthread_attr_t *attr, ++ size_t stacksize); ++ ++/* This function returns non-zero if pthread_barrier_wait returned ++ PTHREAD_BARRIER_SERIAL_THREAD. */ ++int xpthread_barrier_wait (pthread_barrier_t *barrier); ++ ++__END_DECLS ++ ++#endif /* SUPPORT_THREAD_H */ +diff --git a/support/xunistd.h b/support/xunistd.h +new file mode 100644 +index 0000000000..151d743e1f +--- /dev/null ++++ b/support/xunistd.h +@@ -0,0 +1,56 @@ ++/* POSIX-specific extra functions. ++ 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 ++ . */ ++ ++/* These wrapper functions use POSIX types and therefore cannot be ++ declared in . */ ++ ++#ifndef SUPPORT_XUNISTD_H ++#define SUPPORT_XUNISTD_H ++ ++#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 xmunmap (void *addr, size_t length); ++ ++__END_DECLS ++ ++#endif /* SUPPORT_XUNISTD_H */ +diff --git a/support/xwaitpid.c b/support/xwaitpid.c +new file mode 100644 +index 0000000000..204795e4c0 +--- /dev/null ++++ b/support/xwaitpid.c +@@ -0,0 +1,33 @@ ++/* waitpid with error checking. ++ 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 ++ ++int ++xwaitpid (int pid, int *status, int flags) ++{ ++ pid_t result = waitpid (pid, status, flags); ++ if (result < 0) ++ FAIL_EXIT1 ("waitpid: %m\n"); ++ return result; ++} +diff --git a/support/xwrite.c b/support/xwrite.c +new file mode 100644 +index 0000000000..134e8ee4c1 +--- /dev/null ++++ b/support/xwrite.c +@@ -0,0 +1,39 @@ ++/* write with error checking and retries. ++ 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 ++ ++void ++xwrite (int fd, const void *buffer, size_t length) ++{ ++ const char *p = buffer; ++ const char *end = p + length; ++ while (p < end) ++ { ++ ssize_t ret = write (fd, p, end - p); ++ if (ret < 0) ++ FAIL_EXIT1 ("write of %zu bytes failed after %td: %m", ++ length, p - (const char *) buffer); ++ if (ret == 0) ++ FAIL_EXIT1 ("write return 0 after writing %td bytes of %zu", ++ p - (const char *) buffer, length); ++ p += ret; ++ } ++} +diff --git a/sysdeps/aarch64/dl-machine.h b/sysdeps/aarch64/dl-machine.h +index 282805e396..e86d8b5b63 100644 +--- a/sysdeps/aarch64/dl-machine.h ++++ b/sysdeps/aarch64/dl-machine.h +@@ -172,8 +172,8 @@ _dl_start_user: \n\ + cmp x0, #0 \n\ + bne 1b \n\ + // Update _dl_argv \n\ +- adrp x3, _dl_argv \n\ +- str x2, [x3, #:lo12:_dl_argv] \n\ ++ adrp x3, __GI__dl_argv \n\ ++ str x2, [x3, #:lo12:__GI__dl_argv] \n\ + .L_done_stack_adjust: \n\ + // compute envp \n\ + add x3, x2, x1, lsl #3 \n\ +diff --git a/sysdeps/aarch64/nptl/tcb-offsets.sym b/sysdeps/aarch64/nptl/tcb-offsets.sym +index 0677aeabff..238647dd47 100644 +--- a/sysdeps/aarch64/nptl/tcb-offsets.sym ++++ b/sysdeps/aarch64/nptl/tcb-offsets.sym +@@ -2,6 +2,5 @@ + #include + + PTHREAD_MULTIPLE_THREADS_OFFSET offsetof (struct pthread, header.multiple_threads) +-PTHREAD_PID_OFFSET offsetof (struct pthread, pid) + PTHREAD_TID_OFFSET offsetof (struct pthread, tid) + PTHREAD_SIZEOF sizeof (struct pthread) +diff --git a/sysdeps/alpha/fpu/s_ceil.c b/sysdeps/alpha/fpu/s_ceil.c +index c1ff864d4b..e9c350af1c 100644 +--- a/sysdeps/alpha/fpu/s_ceil.c ++++ b/sysdeps/alpha/fpu/s_ceil.c +@@ -26,17 +26,16 @@ + double + __ceil (double x) + { ++ if (isnan (x)) ++ return x + x; ++ + if (isless (fabs (x), 9007199254740992.0)) /* 1 << DBL_MANT_DIG */ + { + double tmp1, new_x; + + new_x = -x; + __asm ( +-#ifdef _IEEE_FP_INEXACT +- "cvttq/svim %2,%1\n\t" +-#else + "cvttq/svm %2,%1\n\t" +-#endif + "cvtqt/m %1,%0\n\t" + : "=f"(new_x), "=&f"(tmp1) + : "f"(new_x)); +diff --git a/sysdeps/alpha/fpu/s_ceilf.c b/sysdeps/alpha/fpu/s_ceilf.c +index 7e63a6fe94..77e01a99f7 100644 +--- a/sysdeps/alpha/fpu/s_ceilf.c ++++ b/sysdeps/alpha/fpu/s_ceilf.c +@@ -25,6 +25,9 @@ + float + __ceilf (float x) + { ++ if (isnanf (x)) ++ return x + x; ++ + if (isless (fabsf (x), 16777216.0f)) /* 1 << FLT_MANT_DIG */ + { + /* Note that Alpha S_Floating is stored in registers in a +@@ -36,11 +39,7 @@ __ceilf (float x) + + new_x = -x; + __asm ("cvtst/s %3,%2\n\t" +-#ifdef _IEEE_FP_INEXACT +- "cvttq/svim %2,%1\n\t" +-#else + "cvttq/svm %2,%1\n\t" +-#endif + "cvtqt/m %1,%0\n\t" + : "=f"(new_x), "=&f"(tmp1), "=&f"(tmp2) + : "f"(new_x)); +diff --git a/sysdeps/alpha/fpu/s_floor.c b/sysdeps/alpha/fpu/s_floor.c +index 1a6f8c4617..9930f6be42 100644 +--- a/sysdeps/alpha/fpu/s_floor.c ++++ b/sysdeps/alpha/fpu/s_floor.c +@@ -27,16 +27,15 @@ + double + __floor (double x) + { ++ if (isnan (x)) ++ return x + x; ++ + if (isless (fabs (x), 9007199254740992.0)) /* 1 << DBL_MANT_DIG */ + { + double tmp1, new_x; + + __asm ( +-#ifdef _IEEE_FP_INEXACT +- "cvttq/svim %2,%1\n\t" +-#else + "cvttq/svm %2,%1\n\t" +-#endif + "cvtqt/m %1,%0\n\t" + : "=f"(new_x), "=&f"(tmp1) + : "f"(x)); +diff --git a/sysdeps/alpha/fpu/s_floorf.c b/sysdeps/alpha/fpu/s_floorf.c +index 8cd80e2b42..015c04f40d 100644 +--- a/sysdeps/alpha/fpu/s_floorf.c ++++ b/sysdeps/alpha/fpu/s_floorf.c +@@ -26,6 +26,9 @@ + float + __floorf (float x) + { ++ if (isnanf (x)) ++ return x + x; ++ + if (isless (fabsf (x), 16777216.0f)) /* 1 << FLT_MANT_DIG */ + { + /* Note that Alpha S_Floating is stored in registers in a +@@ -36,11 +39,7 @@ __floorf (float x) + float tmp1, tmp2, new_x; + + __asm ("cvtst/s %3,%2\n\t" +-#ifdef _IEEE_FP_INEXACT +- "cvttq/svim %2,%1\n\t" +-#else + "cvttq/svm %2,%1\n\t" +-#endif + "cvtqt/m %1,%0\n\t" + : "=f"(new_x), "=&f"(tmp1), "=&f"(tmp2) + : "f"(x)); +diff --git a/sysdeps/alpha/fpu/s_rint.c b/sysdeps/alpha/fpu/s_rint.c +index f33fe72c11..259348afc0 100644 +--- a/sysdeps/alpha/fpu/s_rint.c ++++ b/sysdeps/alpha/fpu/s_rint.c +@@ -23,6 +23,9 @@ + double + __rint (double x) + { ++ if (isnan (x)) ++ return x + x; ++ + if (isless (fabs (x), 9007199254740992.0)) /* 1 << DBL_MANT_DIG */ + { + double tmp1, new_x; +diff --git a/sysdeps/alpha/fpu/s_rintf.c b/sysdeps/alpha/fpu/s_rintf.c +index 1400dfe8d7..645728ad5b 100644 +--- a/sysdeps/alpha/fpu/s_rintf.c ++++ b/sysdeps/alpha/fpu/s_rintf.c +@@ -22,6 +22,9 @@ + float + __rintf (float x) + { ++ if (isnanf (x)) ++ return x + x; ++ + if (isless (fabsf (x), 16777216.0f)) /* 1 << FLT_MANT_DIG */ + { + /* Note that Alpha S_Floating is stored in registers in a +diff --git a/sysdeps/alpha/fpu/s_trunc.c b/sysdeps/alpha/fpu/s_trunc.c +index 16cb114a72..4b986a6926 100644 +--- a/sysdeps/alpha/fpu/s_trunc.c ++++ b/sysdeps/alpha/fpu/s_trunc.c +@@ -28,12 +28,11 @@ __trunc (double x) + double two52 = copysign (0x1.0p52, x); + double r, tmp; + ++ if (isgreaterequal (fabs (x), 0x1.0p52)) ++ return x; ++ + __asm ( +-#ifdef _IEEE_FP_INEXACT +- "addt/suic %2, %3, %1\n\tsubt/suic %1, %3, %0" +-#else + "addt/suc %2, %3, %1\n\tsubt/suc %1, %3, %0" +-#endif + : "=&f"(r), "=&f"(tmp) + : "f"(x), "f"(two52)); + +diff --git a/sysdeps/alpha/fpu/s_truncf.c b/sysdeps/alpha/fpu/s_truncf.c +index 2290f28295..3e93356166 100644 +--- a/sysdeps/alpha/fpu/s_truncf.c ++++ b/sysdeps/alpha/fpu/s_truncf.c +@@ -27,12 +27,11 @@ __truncf (float x) + float two23 = copysignf (0x1.0p23, x); + float r, tmp; + ++ if (isgreaterequal (fabsf (x), 0x1.0p23)) ++ return x; ++ + __asm ( +-#ifdef _IEEE_FP_INEXACT +- "adds/suic %2, %3, %1\n\tsubs/suic %1, %3, %0" +-#else + "adds/suc %2, %3, %1\n\tsubs/suc %1, %3, %0" +-#endif + : "=&f"(r), "=&f"(tmp) + : "f"(x), "f"(two23)); + +diff --git a/sysdeps/alpha/nptl/tcb-offsets.sym b/sysdeps/alpha/nptl/tcb-offsets.sym +index c21a791040..1005621b37 100644 +--- a/sysdeps/alpha/nptl/tcb-offsets.sym ++++ b/sysdeps/alpha/nptl/tcb-offsets.sym +@@ -10,5 +10,4 @@ + #define thread_offsetof(mem) (long)(offsetof(struct pthread, mem) - sizeof(struct pthread)) + + MULTIPLE_THREADS_OFFSET thread_offsetof (header.multiple_threads) +-PID_OFFSET thread_offsetof (pid) + TID_OFFSET thread_offsetof (tid) +diff --git a/sysdeps/arm/nacl/libc.abilist b/sysdeps/arm/nacl/libc.abilist +index 2f7751d167..dfa7198306 100644 +--- a/sysdeps/arm/nacl/libc.abilist ++++ b/sysdeps/arm/nacl/libc.abilist +@@ -1840,4 +1840,5 @@ GLIBC_2.23 fts64_close F + GLIBC_2.23 fts64_open F + GLIBC_2.23 fts64_read F + GLIBC_2.23 fts64_set F ++GLIBC_2.24 GLIBC_2.24 A + GLIBC_2.24 quick_exit F +diff --git a/sysdeps/arm/nptl/tcb-offsets.sym b/sysdeps/arm/nptl/tcb-offsets.sym +index 92cc441d3d..bf9c0a1c17 100644 +--- a/sysdeps/arm/nptl/tcb-offsets.sym ++++ b/sysdeps/arm/nptl/tcb-offsets.sym +@@ -7,5 +7,4 @@ + #define thread_offsetof(mem) (long)(offsetof(struct pthread, mem) - sizeof(struct pthread)) + + MULTIPLE_THREADS_OFFSET thread_offsetof (header.multiple_threads) +-PID_OFFSET thread_offsetof (pid) + TID_OFFSET thread_offsetof (tid) +diff --git a/sysdeps/generic/unsecvars.h b/sysdeps/generic/unsecvars.h +index d5b8119c9c..ac57bd5db0 100644 +--- a/sysdeps/generic/unsecvars.h ++++ b/sysdeps/generic/unsecvars.h +@@ -4,11 +4,13 @@ + #define UNSECURE_ENVVARS \ + "GCONV_PATH\0" \ + "GETCONF_DIR\0" \ ++ "GLIBC_TUNABLES\0" \ + "HOSTALIASES\0" \ + "LD_AUDIT\0" \ + "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/dl-machine.h b/sysdeps/hppa/dl-machine.h +index 9404211819..01bd5bf197 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/nptl/tcb-offsets.sym b/sysdeps/hppa/nptl/tcb-offsets.sym +index c2f326ee3d..6e852f35b1 100644 +--- a/sysdeps/hppa/nptl/tcb-offsets.sym ++++ b/sysdeps/hppa/nptl/tcb-offsets.sym +@@ -3,7 +3,6 @@ + + RESULT offsetof (struct pthread, result) + TID offsetof (struct pthread, tid) +-PID offsetof (struct pthread, pid) + CANCELHANDLING offsetof (struct pthread, cancelhandling) + CLEANUP_JMP_BUF offsetof (struct pthread, cleanup_jmp_buf) + MULTIPLE_THREADS_OFFSET offsetof (struct pthread, header.multiple_threads) +@@ -14,6 +13,5 @@ MUTEX_FUTEX offsetof (pthread_mutex_t, __data.__lock) + -- This way we get the offset of a member in the struct pthread that + -- preceeds the thread pointer (which points to the dtv). + #define thread_offsetof(mem) (unsigned int)(offsetof(struct pthread, mem) - sizeof(struct pthread)) +-PID_THREAD_OFFSET thread_offsetof (pid) + TID_THREAD_OFFSET thread_offsetof (tid) + MULTIPLE_THREADS_THREAD_OFFSET thread_offsetof (header.multiple_threads) +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/i386/nptl/tcb-offsets.sym b/sysdeps/i386/nptl/tcb-offsets.sym +index 7bdf161b29..695a810386 100644 +--- a/sysdeps/i386/nptl/tcb-offsets.sym ++++ b/sysdeps/i386/nptl/tcb-offsets.sym +@@ -4,7 +4,6 @@ + + RESULT offsetof (struct pthread, result) + TID offsetof (struct pthread, tid) +-PID offsetof (struct pthread, pid) + CANCELHANDLING offsetof (struct pthread, cancelhandling) + CLEANUP_JMP_BUF offsetof (struct pthread, cleanup_jmp_buf) + MULTIPLE_THREADS_OFFSET offsetof (tcbhead_t, multiple_threads) +diff --git a/sysdeps/ia64/nptl/Makefile b/sysdeps/ia64/nptl/Makefile +index 48f1327446..1e6be8eea8 100644 +--- a/sysdeps/ia64/nptl/Makefile ++++ b/sysdeps/ia64/nptl/Makefile +@@ -21,4 +21,5 @@ endif + + ifeq ($(subdir),nptl) + libpthread-routines += ptw-sysdep ptw-sigblock ptw-sigprocmask ++libpthread-shared-only-routines += ptw-sysdep ptw-sigblock ptw-sigprocmask + endif +diff --git a/sysdeps/ia64/nptl/tcb-offsets.sym b/sysdeps/ia64/nptl/tcb-offsets.sym +index e1707ab1c8..b01f712be2 100644 +--- a/sysdeps/ia64/nptl/tcb-offsets.sym ++++ b/sysdeps/ia64/nptl/tcb-offsets.sym +@@ -1,7 +1,6 @@ + #include + #include + +-PID offsetof (struct pthread, pid) - TLS_PRE_TCB_SIZE + TID offsetof (struct pthread, tid) - TLS_PRE_TCB_SIZE + MULTIPLE_THREADS_OFFSET offsetof (struct pthread, header.multiple_threads) - TLS_PRE_TCB_SIZE + SYSINFO_OFFSET offsetof (tcbhead_t, __private) +diff --git a/sysdeps/ieee754/dbl-64/e_pow.c b/sysdeps/ieee754/dbl-64/e_pow.c +index 663fa392c2..bd758b5979 100644 +--- a/sysdeps/ieee754/dbl-64/e_pow.c ++++ b/sysdeps/ieee754/dbl-64/e_pow.c +@@ -466,15 +466,15 @@ checkint (double x) + return (n & 1) ? -1 : 1; /* odd or even */ + if (k > 20) + { +- if (n << (k - 20)) ++ if (n << (k - 20) != 0) + return 0; /* if not integer */ +- return (n << (k - 21)) ? -1 : 1; ++ return (n << (k - 21) != 0) ? -1 : 1; + } + if (n) + return 0; /*if not integer */ + if (k == 20) + return (m & 1) ? -1 : 1; +- if (m << (k + 12)) ++ if (m << (k + 12) != 0) + return 0; +- return (m << (k + 11)) ? -1 : 1; ++ return (m << (k + 11) != 0) ? -1 : 1; + } +diff --git a/sysdeps/m68k/m680x0/m68020/atomic-machine.h b/sysdeps/m68k/m680x0/m68020/atomic-machine.h +index 24bc5c5ef7..65965cca9e 100644 +--- a/sysdeps/m68k/m680x0/m68020/atomic-machine.h ++++ b/sysdeps/m68k/m680x0/m68020/atomic-machine.h +@@ -73,7 +73,7 @@ typedef uintmax_t uatomic_max_t; + __typeof (mem) __memp = (mem); \ + __asm __volatile ("cas2%.l %0:%R0,%1:%R1,(%2):(%3)" \ + : "=d" (__ret) \ +- : "d" (newval), "r" (__memp), \ ++ : "d" ((__typeof (*(mem))) (newval)), "r" (__memp), \ + "r" ((char *) __memp + 4), "0" (oldval) \ + : "memory"); \ + __ret; }) +@@ -101,8 +101,9 @@ typedef uintmax_t uatomic_max_t; + __asm __volatile ("1: cas2%.l %0:%R0,%1:%R1,(%2):(%3);" \ + " jbne 1b" \ + : "=d" (__result) \ +- : "d" (newvalue), "r" (__memp), \ +- "r" ((char *) __memp + 4), "0" (__result) \ ++ : "d" ((__typeof (*(mem))) (newvalue)), \ ++ "r" (__memp), "r" ((char *) __memp + 4), \ ++ "0" (__result) \ + : "memory"); \ + } \ + __result; }) +@@ -144,7 +145,7 @@ typedef uintmax_t uatomic_max_t; + " cas2%.l %0:%R0,%1:%R1,(%3):(%4);" \ + " jbne 1b" \ + : "=d" (__result), "=&d" (__temp) \ +- : "d" (value), "r" (__memp), \ ++ : "d" ((__typeof (*(mem))) (value)), "r" (__memp), \ + "r" ((char *) __memp + 4), "0" (__result) \ + : "memory"); \ + } \ +@@ -175,8 +176,9 @@ typedef uintmax_t uatomic_max_t; + " cas2%.l %0:%R0,%1:%R1,(%3):(%4);" \ + " jbne 1b" \ + : "=d" (__oldval), "=&d" (__temp) \ +- : "d" (value), "r" (__memp), \ +- "r" ((char *) __memp + 4), "0" (__oldval) \ ++ : "d" ((__typeof (*(mem))) (value)), \ ++ "r" (__memp), "r" ((char *) __memp + 4), \ ++ "0" (__oldval) \ + : "memory"); \ + } \ + }) +diff --git a/sysdeps/m68k/nptl/tcb-offsets.sym b/sysdeps/m68k/nptl/tcb-offsets.sym +index b1bba65868..241fb8b47c 100644 +--- a/sysdeps/m68k/nptl/tcb-offsets.sym ++++ b/sysdeps/m68k/nptl/tcb-offsets.sym +@@ -7,5 +7,4 @@ + #define thread_offsetof(mem) (long)(offsetof(struct pthread, mem) - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE) + + MULTIPLE_THREADS_OFFSET thread_offsetof (header.multiple_threads) +-PID_OFFSET thread_offsetof (pid) + TID_OFFSET thread_offsetof (tid) +diff --git a/sysdeps/microblaze/nptl/tcb-offsets.sym b/sysdeps/microblaze/nptl/tcb-offsets.sym +index 18afbee291..614f0dfed6 100644 +--- a/sysdeps/microblaze/nptl/tcb-offsets.sym ++++ b/sysdeps/microblaze/nptl/tcb-offsets.sym +@@ -7,5 +7,4 @@ + #define thread_offsetof(mem) (long)(offsetof (struct pthread, mem) - sizeof (struct pthread)) + + MULTIPLE_THREADS_OFFSET thread_offsetof (header.multiple_threads) +-PID_OFFSET thread_offsetof (pid) + TID_OFFSET thread_offsetof (tid) +diff --git a/sysdeps/mips/Makefile b/sysdeps/mips/Makefile +index 3d3552322b..7c1d77941e 100644 +--- a/sysdeps/mips/Makefile ++++ b/sysdeps/mips/Makefile +@@ -9,6 +9,7 @@ endif + + ifeq ($(subdir),rt) + librt-sysdep_routines += rt-sysdep ++librt-shared-only-routines += rt-sysdep + endif + + ifeq ($(subdir),debug) +diff --git a/sysdeps/mips/mips32/crti.S b/sysdeps/mips/mips32/crti.S +index 5c0ad7328a..dfbbdc4f8f 100644 +--- a/sysdeps/mips/mips32/crti.S ++++ b/sysdeps/mips/mips32/crti.S +@@ -74,6 +74,7 @@ _init: + .reloc 1f,R_MIPS_JALR,PREINIT_FUNCTION + 1: jalr $25 + .Lno_weak_fn: ++ .insn + #else + lw $25,%got(PREINIT_FUNCTION)($28) + .reloc 1f,R_MIPS_JALR,PREINIT_FUNCTION +diff --git a/sysdeps/mips/mips64/n32/crti.S b/sysdeps/mips/mips64/n32/crti.S +index 00b89f3894..afe6d8edaa 100644 +--- a/sysdeps/mips/mips64/n32/crti.S ++++ b/sysdeps/mips/mips64/n32/crti.S +@@ -74,6 +74,7 @@ _init: + .reloc 1f,R_MIPS_JALR,PREINIT_FUNCTION + 1: jalr $25 + .Lno_weak_fn: ++ .insn + #else + lw $25,%got_disp(PREINIT_FUNCTION)($28) + .reloc 1f,R_MIPS_JALR,PREINIT_FUNCTION +diff --git a/sysdeps/mips/mips64/n64/crti.S b/sysdeps/mips/mips64/n64/crti.S +index f59b20c631..4049d29290 100644 +--- a/sysdeps/mips/mips64/n64/crti.S ++++ b/sysdeps/mips/mips64/n64/crti.S +@@ -74,6 +74,7 @@ _init: + .reloc 1f,R_MIPS_JALR,PREINIT_FUNCTION + 1: jalr $25 + .Lno_weak_fn: ++ .insn + #else + ld $25,%got_disp(PREINIT_FUNCTION)($28) + .reloc 1f,R_MIPS_JALR,PREINIT_FUNCTION +diff --git a/sysdeps/mips/nptl/Makefile b/sysdeps/mips/nptl/Makefile +index 117744ffe2..dda154d842 100644 +--- a/sysdeps/mips/nptl/Makefile ++++ b/sysdeps/mips/nptl/Makefile +@@ -21,4 +21,5 @@ endif + + ifeq ($(subdir),nptl) + libpthread-sysdep_routines += nptl-sysdep ++libpthread-shared-only-routines += nptl-sysdep + endif +diff --git a/sysdeps/mips/nptl/tcb-offsets.sym b/sysdeps/mips/nptl/tcb-offsets.sym +index e0e71dc430..9ea25b94a8 100644 +--- a/sysdeps/mips/nptl/tcb-offsets.sym ++++ b/sysdeps/mips/nptl/tcb-offsets.sym +@@ -7,5 +7,4 @@ + #define thread_offsetof(mem) (long)(offsetof(struct pthread, mem) - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE) + + MULTIPLE_THREADS_OFFSET thread_offsetof (header.multiple_threads) +-PID_OFFSET thread_offsetof (pid) + TID_OFFSET thread_offsetof (tid) +diff --git a/sysdeps/nacl/clock.c b/sysdeps/nacl/clock.c +index 664ad650c3..b6fbcfd2dd 100644 +--- a/sysdeps/nacl/clock.c ++++ b/sysdeps/nacl/clock.c +@@ -24,6 +24,6 @@ + clock_t + clock (void) + { +- nacl_abi_clock_t result; ++ nacl_irt_clock_t result; + return NACL_CALL (__nacl_irt_basic.clock (&result), result); + } +diff --git a/sysdeps/nacl/dup.c b/sysdeps/nacl/dup.c +index 34a7cd46d4..cbce3f5a5a 100644 +--- a/sysdeps/nacl/dup.c ++++ b/sysdeps/nacl/dup.c +@@ -27,4 +27,5 @@ __dup (int fd) + int result; + return NACL_CALL (__nacl_irt_fdio.dup (fd, &result), result); + } ++libc_hidden_def (__dup) + weak_alias (__dup, dup) +diff --git a/sysdeps/nios2/nptl/tcb-offsets.sym b/sysdeps/nios2/nptl/tcb-offsets.sym +index d9ae952585..3cd8d984ac 100644 +--- a/sysdeps/nios2/nptl/tcb-offsets.sym ++++ b/sysdeps/nios2/nptl/tcb-offsets.sym +@@ -9,6 +9,5 @@ + # define thread_offsetof(mem) ((ptrdiff_t) THREAD_SELF + offsetof (struct pthread, mem)) + + MULTIPLE_THREADS_OFFSET thread_offsetof (header.multiple_threads) +-PID_OFFSET thread_offsetof (pid) + TID_OFFSET thread_offsetof (tid) + POINTER_GUARD (offsetof (tcbhead_t, pointer_guard) - TLS_TCB_OFFSET - sizeof (tcbhead_t)) +diff --git a/sysdeps/nptl/fork.c b/sysdeps/nptl/fork.c +index 616d897a36..a5d1e86d71 100644 +--- a/sysdeps/nptl/fork.c ++++ b/sysdeps/nptl/fork.c +@@ -131,16 +131,6 @@ __libc_fork (void) + __malloc_fork_lock_parent (); + } + +-#ifndef NDEBUG +- pid_t ppid = THREAD_GETMEM (THREAD_SELF, tid); +-#endif +- +- /* We need to prevent the getpid() code to update the PID field so +- that, if a signal arrives in the child very early and the signal +- handler uses getpid(), the value returned is correct. */ +- pid_t parentpid = THREAD_GETMEM (THREAD_SELF, pid); +- THREAD_SETMEM (THREAD_SELF, pid, -parentpid); +- + #ifdef ARCH_FORK + pid = ARCH_FORK (); + #else +@@ -153,15 +143,10 @@ __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; + +- /* Adjust the PID field for the new process. */ +- THREAD_SETMEM (self, pid, THREAD_GETMEM (self, tid)); +- + #if HP_TIMING_AVAIL + /* The CPU clock of the thread and process have to be set to zero. */ + hp_timing_t now; +@@ -231,11 +216,6 @@ __libc_fork (void) + } + else + { +- assert (THREAD_GETMEM (THREAD_SELF, tid) == ppid); +- +- /* Restore the PID value. */ +- THREAD_SETMEM (THREAD_SELF, pid, parentpid); +- + /* Release acquired locks in the multi-threaded case. */ + if (multiple_threads) + { +diff --git a/sysdeps/posix/wait3.c b/sysdeps/posix/wait3.c +index cf43d973a7..73722d2be6 100644 +--- a/sysdeps/posix/wait3.c ++++ b/sysdeps/posix/wait3.c +@@ -33,7 +33,7 @@ __wait3 (int *stat_loc, int options, struct rusage *usage) + __set_errno (ENOSYS); + return (pid_t) -1; + } +- return __waitpid (WAIT_ANY, stat_loc.__iptr, options); ++ return __waitpid (WAIT_ANY, stat_loc, options); + } + + weak_alias (__wait3, wait3) +diff --git a/sysdeps/powerpc/fpu/libm-test-ulps b/sysdeps/powerpc/fpu/libm-test-ulps +index 7f37c813d0..36b700c520 100644 +--- a/sysdeps/powerpc/fpu/libm-test-ulps ++++ b/sysdeps/powerpc/fpu/libm-test-ulps +@@ -36,8 +36,8 @@ double: 2 + float: 2 + idouble: 2 + ifloat: 2 +-ildouble: 1 +-ldouble: 1 ++ildouble: 2 ++ldouble: 2 + + Function: "acosh_downward": + double: 1 +@@ -52,8 +52,8 @@ double: 2 + float: 2 + idouble: 2 + ifloat: 2 +-ildouble: 3 +-ldouble: 3 ++ildouble: 4 ++ldouble: 4 + + Function: "acosh_upward": + double: 2 +@@ -122,8 +122,8 @@ double: 3 + float: 3 + idouble: 3 + ifloat: 3 +-ildouble: 4 +-ldouble: 4 ++ildouble: 7 ++ldouble: 7 + + Function: "atan": + double: 1 +@@ -216,8 +216,8 @@ double: 3 + float: 3 + idouble: 3 + ifloat: 3 +-ildouble: 3 +-ldouble: 3 ++ildouble: 4 ++ldouble: 4 + + Function: "cabs": + double: 1 +@@ -272,8 +272,8 @@ double: 5 + float: 3 + idouble: 5 + ifloat: 3 +-ildouble: 5 +-ldouble: 5 ++ildouble: 8 ++ldouble: 8 + + Function: Real part of "cacos_towardzero": + double: 2 +@@ -288,8 +288,8 @@ double: 5 + float: 3 + idouble: 5 + ifloat: 3 +-ildouble: 5 +-ldouble: 5 ++ildouble: 8 ++ldouble: 8 + + Function: Real part of "cacos_upward": + double: 2 +@@ -328,8 +328,8 @@ double: 5 + float: 3 + idouble: 5 + ifloat: 3 +-ildouble: 5 +-ldouble: 5 ++ildouble: 8 ++ldouble: 8 + + Function: Imaginary part of "cacosh_downward": + double: 2 +@@ -344,8 +344,8 @@ double: 5 + float: 3 + idouble: 5 + ifloat: 3 +-ildouble: 5 +-ldouble: 5 ++ildouble: 8 ++ldouble: 8 + + Function: Imaginary part of "cacosh_towardzero": + double: 2 +@@ -432,8 +432,8 @@ double: 5 + float: 3 + idouble: 5 + ifloat: 3 +-ildouble: 5 +-ldouble: 5 ++ildouble: 8 ++ldouble: 8 + + Function: Real part of "casin_towardzero": + double: 3 +@@ -448,8 +448,8 @@ double: 5 + float: 3 + idouble: 5 + ifloat: 3 +-ildouble: 5 +-ldouble: 5 ++ildouble: 8 ++ldouble: 8 + + Function: Real part of "casin_upward": + double: 2 +@@ -488,8 +488,8 @@ double: 5 + float: 3 + idouble: 5 + ifloat: 3 +-ildouble: 5 +-ldouble: 5 ++ildouble: 8 ++ldouble: 8 + + Function: Imaginary part of "casinh_downward": + double: 3 +@@ -504,8 +504,8 @@ double: 5 + float: 3 + idouble: 5 + ifloat: 3 +-ildouble: 5 +-ldouble: 5 ++ildouble: 8 ++ldouble: 8 + + Function: Imaginary part of "casinh_towardzero": + double: 3 +@@ -696,8 +696,8 @@ double: 1 + float: 1 + idouble: 1 + ifloat: 1 +-ildouble: 1 +-ldouble: 1 ++ildouble: 2 ++ldouble: 2 + + Function: Real part of "ccos_downward": + double: 1 +@@ -1132,8 +1132,8 @@ double: 1 + float: 1 + idouble: 1 + ifloat: 1 +-ildouble: 1 +-ldouble: 1 ++ildouble: 2 ++ldouble: 2 + + Function: Imaginary part of "csin": + ildouble: 1 +@@ -1198,8 +1198,8 @@ double: 1 + float: 1 + idouble: 1 + ifloat: 1 +-ildouble: 1 +-ldouble: 1 ++ildouble: 2 ++ldouble: 2 + + Function: Real part of "csinh_downward": + double: 2 +@@ -1318,8 +1318,8 @@ double: 1 + float: 1 + idouble: 1 + ifloat: 1 +-ildouble: 2 +-ldouble: 2 ++ildouble: 3 ++ldouble: 3 + + Function: Imaginary part of "ctan": + double: 2 +@@ -1390,8 +1390,8 @@ double: 2 + float: 1 + idouble: 2 + ifloat: 1 +-ildouble: 2 +-ldouble: 2 ++ildouble: 3 ++ldouble: 3 + + Function: Real part of "ctanh_downward": + double: 4 +@@ -1478,8 +1478,8 @@ double: 2 + float: 2 + idouble: 2 + ifloat: 2 +-ildouble: 2 +-ldouble: 2 ++ildouble: 3 ++ldouble: 3 + + Function: "erfc_downward": + double: 3 +@@ -1564,8 +1564,8 @@ double: 1 + float: 1 + idouble: 1 + ifloat: 1 +-ildouble: 1 +-ldouble: 1 ++ildouble: 2 ++ldouble: 2 + + Function: "exp2_upward": + double: 1 +@@ -1588,8 +1588,8 @@ ildouble: 2 + ldouble: 2 + + Function: "exp_upward": +-float: 1 + double: 1 ++float: 1 + idouble: 1 + ifloat: 1 + ildouble: 1 +@@ -1624,8 +1624,8 @@ double: 1 + float: 1 + idouble: 1 + ifloat: 1 +-ildouble: 4 +-ldouble: 4 ++ildouble: 6 ++ldouble: 6 + + Function: "fma": + ildouble: 1 +@@ -1688,8 +1688,8 @@ double: 4 + float: 5 + idouble: 4 + ifloat: 5 +-ildouble: 10 +-ldouble: 10 ++ildouble: 11 ++ldouble: 11 + + Function: "hypot": + double: 1 +@@ -1752,8 +1752,8 @@ double: 1 + float: 2 + idouble: 1 + ifloat: 2 +-ildouble: 1 +-ldouble: 1 ++ildouble: 2 ++ldouble: 2 + + Function: "j1_downward": + double: 3 +@@ -1840,8 +1840,8 @@ double: 4 + float: 5 + idouble: 4 + ifloat: 5 +-ildouble: 10 +-ldouble: 10 ++ildouble: 11 ++ldouble: 11 + + Function: "log": + float: 1 +@@ -1910,8 +1910,8 @@ double: 2 + float: 2 + idouble: 2 + ifloat: 2 +-ildouble: 2 +-ldouble: 2 ++ildouble: 3 ++ldouble: 3 + + Function: "log2": + double: 1 +@@ -2184,16 +2184,16 @@ double: 3 + float: 3 + idouble: 3 + ifloat: 3 +-ildouble: 3 +-ldouble: 3 ++ildouble: 4 ++ldouble: 4 + + Function: "tanh_towardzero": + double: 2 + float: 2 + idouble: 2 + ifloat: 2 +-ildouble: 3 +-ldouble: 3 ++ildouble: 4 ++ldouble: 4 + + Function: "tanh_upward": + double: 3 +diff --git a/sysdeps/powerpc/ifunc-sel.h b/sysdeps/powerpc/ifunc-sel.h +index 526d8ed88b..ac589bd3c0 100644 +--- a/sysdeps/powerpc/ifunc-sel.h ++++ b/sysdeps/powerpc/ifunc-sel.h +@@ -17,15 +17,17 @@ ifunc_sel (int (*f1) (void), int (*f2) (void), int (*f3) (void)) + "addis %0,11,%2-1b@ha\n\t" + "addi %0,%0,%2-1b@l\n\t" + "cmpwi 12,1\n\t" +- "beqlr\n\t" ++ "beq 2f\n\t" + "addis %0,11,%3-1b@ha\n\t" + "addi %0,%0,%3-1b@l\n\t" + "cmpwi 12,-1\n\t" +- "beqlr\n\t" ++ "beq 2f\n\t" + "addis %0,11,%4-1b@ha\n\t" +- "addi %0,%0,%4-1b@l" ++ "addi %0,%0,%4-1b@l\n\t" ++ "2:" + : "=r" (ret) +- : "X" (&global), "X" (f1), "X" (f2), "X" (f3)); ++ : "i" (&global), "i" (f1), "i" (f2), "i" (f3) ++ : "11", "12", "cr0"); + return ret; + } + +@@ -40,7 +42,8 @@ ifunc_one (int (*f1) (void)) + "addis %0,%0,%1-1b@ha\n\t" + "addi %0,%0,%1-1b@l" + : "=r" (ret) +- : "X" (f1)); ++ : "i" (f1) ++ : "12"); + return ret; + } + #endif +diff --git a/sysdeps/powerpc/nptl/tcb-offsets.sym b/sysdeps/powerpc/nptl/tcb-offsets.sym +index f580e69555..7c9fd33562 100644 +--- a/sysdeps/powerpc/nptl/tcb-offsets.sym ++++ b/sysdeps/powerpc/nptl/tcb-offsets.sym +@@ -13,7 +13,6 @@ + #if TLS_MULTIPLE_THREADS_IN_TCB + MULTIPLE_THREADS_OFFSET thread_offsetof (header.multiple_threads) + #endif +-PID thread_offsetof (pid) + TID thread_offsetof (tid) + POINTER_GUARD (offsetof (tcbhead_t, pointer_guard) - TLS_TCB_OFFSET - sizeof (tcbhead_t)) + TAR_SAVE (offsetof (tcbhead_t, tar_save) - TLS_TCB_OFFSET - sizeof (tcbhead_t)) +diff --git a/sysdeps/powerpc/powerpc32/power6/memset.S b/sysdeps/powerpc/powerpc32/power6/memset.S +index b2a222edd2..d5dbe83af2 100644 +--- a/sysdeps/powerpc/powerpc32/power6/memset.S ++++ b/sysdeps/powerpc/powerpc32/power6/memset.S +@@ -394,7 +394,7 @@ L(cacheAlignedx): + /* A simple loop for the longer (>640 bytes) lengths. This form limits + the branch miss-predicted to exactly 1 at loop exit.*/ + L(cacheAligned512): +- cmpli cr1,rLEN,128 ++ cmplwi cr1,rLEN,128 + blt cr1,L(cacheAligned1) + dcbz 0,rMEMP + addi rLEN,rLEN,-128 +diff --git a/sysdeps/powerpc/powerpc32/power9/multiarch/Implies b/sysdeps/powerpc/powerpc32/power9/multiarch/Implies +index 4393b56872..1a46ef0035 100644 +--- a/sysdeps/powerpc/powerpc32/power9/multiarch/Implies ++++ b/sysdeps/powerpc/powerpc32/power9/multiarch/Implies +@@ -1 +1 @@ +-powerpc/powerpc32/power8/fpu/multiarch ++powerpc/powerpc32/power8/multiarch +diff --git a/sysdeps/powerpc/powerpc64/power6/memset.S b/sysdeps/powerpc/powerpc64/power6/memset.S +index c2d1c4e600..d445b1e1ef 100644 +--- a/sysdeps/powerpc/powerpc64/power6/memset.S ++++ b/sysdeps/powerpc/powerpc64/power6/memset.S +@@ -251,7 +251,7 @@ L(cacheAlignedx): + /* A simple loop for the longer (>640 bytes) lengths. This form limits + the branch miss-predicted to exactly 1 at loop exit.*/ + L(cacheAligned512): +- cmpli cr1,rLEN,128 ++ cmpldi cr1,rLEN,128 + blt cr1,L(cacheAligned1) + dcbz 0,rMEMP + addi rLEN,rLEN,-128 +diff --git a/sysdeps/powerpc/powerpc64/power9/fpu/Implies b/sysdeps/powerpc/powerpc64/power9/fpu/Implies +index fad2505ab9..ae0dbaf857 100644 +--- a/sysdeps/powerpc/powerpc64/power9/fpu/Implies ++++ b/sysdeps/powerpc/powerpc64/power9/fpu/Implies +@@ -1,2 +1 @@ + powerpc/powerpc64/power8/fpu +-powerpc/powerpc64/power8 +diff --git a/sysdeps/s390/nptl/Makefile b/sysdeps/s390/nptl/Makefile +index 5734b983b0..3a391c8217 100644 +--- a/sysdeps/s390/nptl/Makefile ++++ b/sysdeps/s390/nptl/Makefile +@@ -21,4 +21,5 @@ endif + + ifeq ($(subdir),nptl) + libpthread-routines += ptw-sysdep ++libpthread-shared-only-routines += ptw-sysdep + endif +diff --git a/sysdeps/s390/nptl/tcb-offsets.sym b/sysdeps/s390/nptl/tcb-offsets.sym +index 9cfae211e0..9c1c01f353 100644 +--- a/sysdeps/s390/nptl/tcb-offsets.sym ++++ b/sysdeps/s390/nptl/tcb-offsets.sym +@@ -3,5 +3,4 @@ + + MULTIPLE_THREADS_OFFSET offsetof (tcbhead_t, multiple_threads) + STACK_GUARD offsetof (tcbhead_t, stack_guard) +-PID offsetof (struct pthread, pid) + TID offsetof (struct pthread, tid) +diff --git a/sysdeps/sh/nptl/tcb-offsets.sym b/sysdeps/sh/nptl/tcb-offsets.sym +index ac63b5b93b..4963e1506f 100644 +--- a/sysdeps/sh/nptl/tcb-offsets.sym ++++ b/sysdeps/sh/nptl/tcb-offsets.sym +@@ -4,7 +4,6 @@ + + RESULT offsetof (struct pthread, result) + TID offsetof (struct pthread, tid) +-PID offsetof (struct pthread, pid) + CANCELHANDLING offsetof (struct pthread, cancelhandling) + CLEANUP_JMP_BUF offsetof (struct pthread, cleanup_jmp_buf) + MULTIPLE_THREADS_OFFSET offsetof (struct pthread, header.multiple_threads) +diff --git a/sysdeps/sparc/nptl/tcb-offsets.sym b/sysdeps/sparc/nptl/tcb-offsets.sym +index 923af8a5b7..f75d02065e 100644 +--- a/sysdeps/sparc/nptl/tcb-offsets.sym ++++ b/sysdeps/sparc/nptl/tcb-offsets.sym +@@ -3,5 +3,4 @@ + + MULTIPLE_THREADS_OFFSET offsetof (tcbhead_t, multiple_threads) + POINTER_GUARD offsetof (tcbhead_t, pointer_guard) +-PID offsetof (struct pthread, pid) + TID offsetof (struct pthread, tid) +diff --git a/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/Makefile b/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/Makefile +index ebbe28b07f..13d3c6db51 100644 +--- a/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/Makefile ++++ b/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/Makefile +@@ -4,8 +4,8 @@ libm-sysdep_routines += m_copysignf-vis3 m_copysign-vis3 s_fabs-vis3 \ + s_fabsf-vis3 s_llrintf-vis3 s_llrint-vis3 \ + s_rintf-vis3 s_rint-vis3 w_sqrt-vis3 w_sqrtf-vis3 \ + s_fminf-vis3 s_fmin-vis3 s_fmaxf-vis3 s_fmax-vis3 \ +- s_fmaf-vis3 s_fma-vis3 s_fdimf-vis3 s_fdim-vis3 \ +- s_nearbyint-vis3 s_nearbyintf-vis3 ++ s_fmaf-vis3 s_fma-vis3 s_nearbyint-vis3 \ ++ s_nearbyintf-vis3 + sysdep_routines += s_copysignf-vis3 s_copysign-vis3 + endif + endif +diff --git a/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdim.S b/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdim.S +deleted file mode 100644 +index 4b13408244..0000000000 +--- a/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdim.S ++++ /dev/null +@@ -1,19 +0,0 @@ +-#include +-#include +- +-SPARC_ASM_VIS3_IFUNC(fdim) +- +-weak_alias (__fdim, fdim) +- +-#if LONG_DOUBLE_COMPAT(libm, GLIBC_2_1) +-compat_symbol (libm, __fdim, fdiml, GLIBC_2_1); +-#endif +- +-# undef weak_alias +-# define weak_alias(a, b) +-# undef compat_symbol +-# define compat_symbol(a, b, c, d) +- +-#define __fdim __fdim_generic +- +-#include "../s_fdim.S" +diff --git a/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdimf.S b/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdimf.S +deleted file mode 100644 +index 30381d6a59..0000000000 +--- a/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdimf.S ++++ /dev/null +@@ -1,12 +0,0 @@ +-#include +- +-SPARC_ASM_VIS3_IFUNC(fdimf) +- +-weak_alias (__fdimf, fdimf) +- +-# undef weak_alias +-# define weak_alias(a, b) +- +-#define __fdimf __fdimf_generic +- +-#include "../s_fdimf.S" +diff --git a/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_nearbyint-vis3.S b/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_nearbyint-vis3.S +index d9ff0cc288..ff81b0da83 100644 +--- a/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_nearbyint-vis3.S ++++ b/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_nearbyint-vis3.S +@@ -36,15 +36,15 @@ + #define SIGN_BIT %f12 /* -0.0 */ + + ENTRY (__nearbyint_vis3) ++ sllx %o0, 32, %o0 ++ or %o0, %o1, %o0 ++ movxtod %o0, %f0 + fcmpd %fcc3, %f0, %f0 /* Check for sNaN */ + st %fsr, [%sp + 88] + sethi %hi(TWO_FIFTYTWO), %o2 + sethi %hi(0xf8003e0), %o5 + ld [%sp + 88], %o4 +- sllx %o0, 32, %o0 + or %o5, %lo(0xf8003e0), %o5 +- or %o0, %o1, %o0 +- movxtod %o0, %f0 + andn %o4, %o5, %o4 + fzero ZERO + st %o4, [%sp + 80] +diff --git a/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_nearbyintf-vis3.S b/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_nearbyintf-vis3.S +index 5cd1eb02db..833a0dfc24 100644 +--- a/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_nearbyintf-vis3.S ++++ b/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_nearbyintf-vis3.S +@@ -35,9 +35,9 @@ + #define SIGN_BIT %f12 /* -0.0 */ + + ENTRY (__nearbyintf_vis3) ++ movwtos %o0, %f1 + fcmps %fcc3, %f1, %f1 /* Check for sNaN */ + st %fsr, [%sp + 88] +- movwtos %o0, %f1 + sethi %hi(TWO_TWENTYTHREE), %o2 + sethi %hi(0xf8003e0), %o5 + ld [%sp + 88], %o4 +diff --git a/sysdeps/sparc/sparc32/sparcv9/fpu/s_nearbyint.S b/sysdeps/sparc/sparc32/sparcv9/fpu/s_nearbyint.S +index 84a10971a4..198440a5bc 100644 +--- a/sysdeps/sparc/sparc32/sparcv9/fpu/s_nearbyint.S ++++ b/sysdeps/sparc/sparc32/sparcv9/fpu/s_nearbyint.S +@@ -36,21 +36,21 @@ + #define SIGN_BIT %f12 /* -0.0 */ + + ENTRY (__nearbyint) ++ sllx %o0, 32, %o0 ++ or %o0, %o1, %o0 ++ stx %o0, [%sp + 72] ++ ldd [%sp + 72], %f0 + fcmpd %fcc3, %f0, %f0 /* Check for sNaN */ + st %fsr, [%sp + 88] + sethi %hi(TWO_FIFTYTWO), %o2 + sethi %hi(0xf8003e0), %o5 + ld [%sp + 88], %o4 +- sllx %o0, 32, %o0 + or %o5, %lo(0xf8003e0), %o5 +- or %o0, %o1, %o0 + andn %o4, %o5, %o4 + fzero ZERO + st %o4, [%sp + 80] +- stx %o0, [%sp + 72] + sllx %o2, 32, %o2 + fnegd ZERO, SIGN_BIT +- ldd [%sp + 72], %f0 + ld [%sp + 80], %fsr + stx %o2, [%sp + 72] + fabsd %f0, %f14 +diff --git a/sysdeps/sparc/sparc32/sparcv9/fpu/s_nearbyintf.S b/sysdeps/sparc/sparc32/sparcv9/fpu/s_nearbyintf.S +index d5cf5ce815..9be41f6c22 100644 +--- a/sysdeps/sparc/sparc32/sparcv9/fpu/s_nearbyintf.S ++++ b/sysdeps/sparc/sparc32/sparcv9/fpu/s_nearbyintf.S +@@ -35,9 +35,10 @@ + #define SIGN_BIT %f12 /* -0.0 */ + + ENTRY (__nearbyintf) ++ st %o0, [%sp + 68] ++ ld [%sp + 68], %f1 + fcmps %fcc3, %f1, %f1 /* Check for sNaN */ + st %fsr, [%sp + 88] +- st %o0, [%sp + 68] + sethi %hi(TWO_TWENTYTHREE), %o2 + sethi %hi(0xf8003e0), %o5 + ld [%sp + 88], %o4 +@@ -46,7 +47,6 @@ ENTRY (__nearbyintf) + fnegs ZERO, SIGN_BIT + andn %o4, %o5, %o4 + st %o4, [%sp + 80] +- ld [%sp + 68], %f1 + ld [%sp + 80], %fsr + st %o2, [%sp + 68] + fabss %f1, %f14 +diff --git a/sysdeps/tile/nptl/tcb-offsets.sym b/sysdeps/tile/nptl/tcb-offsets.sym +index 6740bc976f..0147ffafb7 100644 +--- a/sysdeps/tile/nptl/tcb-offsets.sym ++++ b/sysdeps/tile/nptl/tcb-offsets.sym +@@ -9,7 +9,6 @@ + #define thread_offsetof(mem) (long)(offsetof(struct pthread, mem) - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE) + + MULTIPLE_THREADS_OFFSET thread_offsetof (header.multiple_threads) +-PID_OFFSET thread_offsetof (pid) + TID_OFFSET thread_offsetof (tid) + POINTER_GUARD (offsetof (tcbhead_t, pointer_guard) - TLS_TCB_OFFSET - sizeof (tcbhead_t)) + FEEDBACK_DATA_OFFSET (offsetof (tcbhead_t, feedback_data) - TLS_TCB_OFFSET - sizeof (tcbhead_t)) +diff --git a/sysdeps/unix/alpha/Makefile b/sysdeps/unix/alpha/Makefile +index 441aa02a83..0660847f15 100644 +--- a/sysdeps/unix/alpha/Makefile ++++ b/sysdeps/unix/alpha/Makefile +@@ -1,3 +1,4 @@ + ifeq ($(subdir),rt) + librt-sysdep_routines += rt-sysdep ++librt-shared-only-routines += rt-sysdep + endif +diff --git a/sysdeps/unix/sysdep.h b/sysdeps/unix/sysdep.h +index 94a2ce0e37..38c2432002 100644 +--- a/sysdeps/unix/sysdep.h ++++ b/sysdeps/unix/sysdep.h +@@ -24,42 +24,79 @@ + #define SYSCALL__(name, args) PSEUDO (__##name, name, args) + #define SYSCALL(name, args) PSEUDO (name, name, args) + +-#define __SYSCALL0(name) \ ++#define __SYSCALL_CONCAT_X(a,b) a##b ++#define __SYSCALL_CONCAT(a,b) __SYSCALL_CONCAT_X (a, b) ++ ++ ++#define __INTERNAL_SYSCALL0(name, err) \ ++ INTERNAL_SYSCALL (name, err, 0) ++#define __INTERNAL_SYSCALL1(name, err, a1) \ ++ INTERNAL_SYSCALL (name, err, 1, a1) ++#define __INTERNAL_SYSCALL2(name, err, a1, a2) \ ++ INTERNAL_SYSCALL (name, err, 2, a1, a2) ++#define __INTERNAL_SYSCALL3(name, err, a1, a2, a3) \ ++ INTERNAL_SYSCALL (name, err, 3, a1, a2, a3) ++#define __INTERNAL_SYSCALL4(name, err, a1, a2, a3, a4) \ ++ INTERNAL_SYSCALL (name, err, 4, a1, a2, a3, a4) ++#define __INTERNAL_SYSCALL5(name, err, a1, a2, a3, a4, a5) \ ++ INTERNAL_SYSCALL (name, err, 5, a1, a2, a3, a4, a5) ++#define __INTERNAL_SYSCALL6(name, err, a1, a2, a3, a4, a5, a6) \ ++ INTERNAL_SYSCALL (name, err, 6, a1, a2, a3, a4, a5, a6) ++#define __INTERNAL_SYSCALL7(name, err, a1, a2, a3, a4, a5, a6, a7) \ ++ INTERNAL_SYSCALL (name, err, 7, a1, a2, a3, a4, a5, a6, a7) ++ ++#define __INTERNAL_SYSCALL_NARGS_X(a,b,c,d,e,f,g,h,n,o,...) o ++#define __INTERNAL_SYSCALL_NARGS(...) \ ++ __INTERNAL_SYSCALL_NARGS_X (__VA_ARGS__,7,6,5,4,3,2,1,0,) ++#define __INTERNAL_SYSCALL_DISP(b,...) \ ++ __SYSCALL_CONCAT (b,__INTERNAL_SYSCALL_NARGS(__VA_ARGS__))(__VA_ARGS__) ++ ++/* Issue a syscall defined by syscall number plus any other argument required. ++ It is similar to INTERNAL_SYSCALL macro, but without the need to pass the ++ expected argument number as second parameter. */ ++#define INTERNAL_SYSCALL_CALL(...) \ ++ __INTERNAL_SYSCALL_DISP (__INTERNAL_SYSCALL, __VA_ARGS__) ++ ++#define __INLINE_SYSCALL0(name) \ + INLINE_SYSCALL (name, 0) +-#define __SYSCALL1(name, a1) \ ++#define __INLINE_SYSCALL1(name, a1) \ + INLINE_SYSCALL (name, 1, a1) +-#define __SYSCALL2(name, a1, a2) \ ++#define __INLINE_SYSCALL2(name, a1, a2) \ + INLINE_SYSCALL (name, 2, a1, a2) +-#define __SYSCALL3(name, a1, a2, a3) \ ++#define __INLINE_SYSCALL3(name, a1, a2, a3) \ + INLINE_SYSCALL (name, 3, a1, a2, a3) +-#define __SYSCALL4(name, a1, a2, a3, a4) \ ++#define __INLINE_SYSCALL4(name, a1, a2, a3, a4) \ + INLINE_SYSCALL (name, 4, a1, a2, a3, a4) +-#define __SYSCALL5(name, a1, a2, a3, a4, a5) \ ++#define __INLINE_SYSCALL5(name, a1, a2, a3, a4, a5) \ + INLINE_SYSCALL (name, 5, a1, a2, a3, a4, a5) +-#define __SYSCALL6(name, a1, a2, a3, a4, a5, a6) \ ++#define __INLINE_SYSCALL6(name, a1, a2, a3, a4, a5, a6) \ + INLINE_SYSCALL (name, 6, a1, a2, a3, a4, a5, a6) +-#define __SYSCALL7(name, a1, a2, a3, a4, a5, a6, a7) \ ++#define __INLINE_SYSCALL7(name, a1, a2, a3, a4, a5, a6, a7) \ + INLINE_SYSCALL (name, 7, a1, a2, a3, a4, a5, a6, a7) + +-#define __SYSCALL_NARGS_X(a,b,c,d,e,f,g,h,n,...) n +-#define __SYSCALL_NARGS(...) \ +- __SYSCALL_NARGS_X (__VA_ARGS__,7,6,5,4,3,2,1,0,) +-#define __SYSCALL_CONCAT_X(a,b) a##b +-#define __SYSCALL_CONCAT(a,b) __SYSCALL_CONCAT_X (a, b) +-#define __SYSCALL_DISP(b,...) \ +- __SYSCALL_CONCAT (b,__SYSCALL_NARGS(__VA_ARGS__))(__VA_ARGS__) ++#define __INLINE_SYSCALL_NARGS_X(a,b,c,d,e,f,g,h,n,...) n ++#define __INLINE_SYSCALL_NARGS(...) \ ++ __INLINE_SYSCALL_NARGS_X (__VA_ARGS__,7,6,5,4,3,2,1,0,) ++#define __INLINE_SYSCALL_DISP(b,...) \ ++ __SYSCALL_CONCAT (b,__INLINE_SYSCALL_NARGS(__VA_ARGS__))(__VA_ARGS__) + +-#define __SYSCALL_CALL(...) __SYSCALL_DISP (__SYSCALL, __VA_ARGS__) ++/* Issue a syscall defined by syscall number plus any other argument ++ required. Any error will be handled using arch defined macros and errno ++ will be set accordingly. ++ It is similar to INLINE_SYSCALL macro, but without the need to pass the ++ expected argument number as second parameter. */ ++#define INLINE_SYSCALL_CALL(...) \ ++ __INLINE_SYSCALL_DISP (__INLINE_SYSCALL, __VA_ARGS__) + + #define SYSCALL_CANCEL(...) \ + ({ \ + long int sc_ret; \ + if (SINGLE_THREAD_P) \ +- sc_ret = __SYSCALL_CALL (__VA_ARGS__); \ ++ sc_ret = INLINE_SYSCALL_CALL (__VA_ARGS__); \ + else \ + { \ + int sc_cancel_oldtype = LIBC_CANCEL_ASYNC (); \ +- sc_ret = __SYSCALL_CALL (__VA_ARGS__); \ ++ sc_ret = INLINE_SYSCALL_CALL (__VA_ARGS__); \ + LIBC_CANCEL_RESET (sc_cancel_oldtype); \ + } \ + sc_ret; \ +diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile +index 35e1ed48d2..32beaa67d0 100644 +--- a/sysdeps/unix/sysv/linux/Makefile ++++ b/sysdeps/unix/sysv/linux/Makefile +@@ -140,7 +140,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/aarch64/clone.S b/sysdeps/unix/sysv/linux/aarch64/clone.S +index 76baa7a698..96482e53c0 100644 +--- a/sysdeps/unix/sysv/linux/aarch64/clone.S ++++ b/sysdeps/unix/sysv/linux/aarch64/clone.S +@@ -72,16 +72,6 @@ thread_start: + cfi_undefined (x30) + mov x29, 0 + +- tbnz x11, #CLONE_VM_BIT, 1f +- +- mov x8, #SYS_ify(getpid) +- svc 0x0 +- mrs x1, tpidr_el0 +- sub x1, x1, #PTHREAD_SIZEOF +- str w0, [x1, #PTHREAD_PID_OFFSET] +- str w0, [x1, #PTHREAD_TID_OFFSET] +-1: +- + /* Pick the function arg and execute. */ + mov x0, x12 + blr x10 +diff --git a/sysdeps/unix/sysv/linux/aarch64/vfork.S b/sysdeps/unix/sysv/linux/aarch64/vfork.S +index 577895eeb2..aeed0b29ce 100644 +--- a/sysdeps/unix/sysv/linux/aarch64/vfork.S ++++ b/sysdeps/unix/sysv/linux/aarch64/vfork.S +@@ -27,27 +27,10 @@ + + ENTRY (__vfork) + +- /* Save the TCB-cached PID away in w3, and then negate the TCB +- field. But if it's zero, set it to 0x80000000 instead. See +- raise.c for the logic that relies on this value. */ +- mrs x2, tpidr_el0 +- sub x2, x2, #PTHREAD_SIZEOF +- ldr w3, [x2, #PTHREAD_PID_OFFSET] +- mov w1, #0x80000000 +- negs w0, w3 +- csel w0, w1, w0, eq +- str w0, [x2, #PTHREAD_PID_OFFSET] +- + mov x0, #0x4111 /* CLONE_VM | CLONE_VFORK | SIGCHLD */ + mov x1, sp + DO_CALL (clone, 2) + +- /* Restore the original value of the TCB cache of the PID, if we're +- the parent. But in the child (syscall return value equals zero), +- leave things as they are. */ +- cbz x0, 1f +- str w3, [x2, #PTHREAD_PID_OFFSET] +-1: + cmn x0, #4095 + b.cs .Lsyscall_error + RET +diff --git a/sysdeps/unix/sysv/linux/alpha/Makefile b/sysdeps/unix/sysv/linux/alpha/Makefile +index c089545e9b..3b523b70cf 100644 +--- a/sysdeps/unix/sysv/linux/alpha/Makefile ++++ b/sysdeps/unix/sysv/linux/alpha/Makefile +@@ -40,4 +40,5 @@ endif # math + ifeq ($(subdir),nptl) + # pull in __syscall_error routine, __sigprocmask, __syscall_rt_sigaction + libpthread-routines += ptw-sysdep ptw-sigprocmask ptw-rt_sigaction ++libpthread-shared-only-routines += ptw-sysdep ptw-sigprocmask ptw-rt_sigaction + endif +diff --git a/sysdeps/unix/sysv/linux/alpha/clone.S b/sysdeps/unix/sysv/linux/alpha/clone.S +index 6a3154f9a7..2757bf20c3 100644 +--- a/sysdeps/unix/sysv/linux/alpha/clone.S ++++ b/sysdeps/unix/sysv/linux/alpha/clone.S +@@ -91,13 +91,6 @@ thread_start: + cfi_def_cfa_register(fp) + cfi_undefined(ra) + +- /* Check and see if we need to reset the PID. */ +- ldq t0, 16(sp) +- lda t1, CLONE_VM +- and t0, t1, t2 +- beq t2, 2f +-1: +- + /* Load up the arguments. */ + ldq pv, 0(sp) + ldq a0, 8(sp) +@@ -120,15 +113,6 @@ thread_start: + halt + + .align 4 +-2: +- rduniq +- mov v0, s0 +- lda v0, __NR_getxpid +- callsys +-3: +- stl v0, PID_OFFSET(s0) +- stl v0, TID_OFFSET(s0) +- br 1b + cfi_endproc + .end thread_start + +diff --git a/sysdeps/unix/sysv/linux/alpha/glob.c b/sysdeps/unix/sysv/linux/alpha/glob.c +index c5dfb85468..19eb9b1c07 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/vfork.S b/sysdeps/unix/sysv/linux/alpha/vfork.S +index 9fc199ac41..e5f7ed0661 100644 +--- a/sysdeps/unix/sysv/linux/alpha/vfork.S ++++ b/sysdeps/unix/sysv/linux/alpha/vfork.S +@@ -25,24 +25,9 @@ ENTRY(__libc_vfork) + rduniq + mov v0, a1 + +- /* Save the TCB-cached PID away in A2, and then negate the TCB +- field. But if it's zero, set it to 0x80000000 instead. See +- raise.c for the logic that relies on this value. */ +- ldl a2, PID_OFFSET(v0) +- ldah t0, -0x8000 +- negl a2, t1 +- cmovne a2, t1, t0 +- stl t0, PID_OFFSET(v0); +- + lda v0, SYS_ify(vfork) + call_pal PAL_callsys + +- /* Restore the original value of the TCB cache of the PID, if we're +- the parent. But in the child (syscall return value equals zero), +- leave things as they are. */ +- beq v0, 1f +- stl a2, PID_OFFSET(a1) +-1: + /* Normal error check and return. */ + bne a3, SYSCALL_ERROR_LABEL + ret +diff --git a/sysdeps/unix/sysv/linux/arm/clone.S b/sysdeps/unix/sysv/linux/arm/clone.S +index 7ff681804b..4c6325d088 100644 +--- a/sysdeps/unix/sysv/linux/arm/clone.S ++++ b/sysdeps/unix/sysv/linux/arm/clone.S +@@ -70,16 +70,6 @@ PSEUDO_END (__clone) + 1: + .fnstart + .cantunwind +- tst ip, #CLONE_VM +- bne 2f +- GET_TLS (lr) +- mov r1, r0 +- ldr r7, =SYS_ify(getpid) +- swi 0x0 +- NEGOFF_ADJ_BASE (r1, TID_OFFSET) +- str r0, NEGOFF_OFF1 (r1, TID_OFFSET) +- str r0, NEGOFF_OFF2 (r1, PID_OFFSET, TID_OFFSET) +-2: + @ pick the function arg and call address off the stack and execute + ldr r0, [sp, #4] + ldr ip, [sp], #8 +diff --git a/sysdeps/unix/sysv/linux/arm/setcontext.S b/sysdeps/unix/sysv/linux/arm/setcontext.S +index 603e508858..d1f168fece 100644 +--- a/sysdeps/unix/sysv/linux/arm/setcontext.S ++++ b/sysdeps/unix/sysv/linux/arm/setcontext.S +@@ -86,12 +86,19 @@ weak_alias(__setcontext, setcontext) + + /* Called when a makecontext() context returns. Start the + context in R4 or fall through to exit(). */ ++ /* Unwind descriptors are looked up based on PC - 2, so we have to ++ make sure to mark the instruction preceding the __startcontext ++ label as .cantunwind. */ ++ .fnstart ++ .cantunwind ++ nop + ENTRY(__startcontext) + movs r0, r4 + bne PLTJMP(__setcontext) + + @ New context was 0 - exit + b PLTJMP(HIDDEN_JUMPTARGET(exit)) ++ .fnend + END(__startcontext) + + #ifdef PIC +diff --git a/sysdeps/unix/sysv/linux/arm/vfork.S b/sysdeps/unix/sysv/linux/arm/vfork.S +index 500f5ca4be..794372ee12 100644 +--- a/sysdeps/unix/sysv/linux/arm/vfork.S ++++ b/sysdeps/unix/sysv/linux/arm/vfork.S +@@ -28,16 +28,6 @@ + and the process ID of the new process to the old process. */ + + ENTRY (__vfork) +- /* Save the PID value. */ +- GET_TLS (r2) +- NEGOFF_ADJ_BASE2 (r2, r0, PID_OFFSET) /* Save the TLS addr in r2. */ +- ldr r3, NEGOFF_OFF1 (r2, PID_OFFSET) /* Load the saved PID. */ +- rsbs r0, r3, #0 /* Negate it, and test for zero. */ +- /* Use 0x80000000 if it was 0. See raise.c for how this is used. */ +- it eq +- moveq r0, #0x80000000 +- str r0, NEGOFF_OFF1 (r2, PID_OFFSET) /* Store the temp PID. */ +- + /* The DO_CALL macro saves r7 on the stack, to enable generation + of ARM unwind info. Since the stack is initially shared between + parent and child of vfork, that saved value could be corrupted. +@@ -57,11 +47,6 @@ ENTRY (__vfork) + mov r7, ip + cfi_restore (r7) + +- /* Restore the old PID value in the parent. */ +- cmp r0, #0 /* If we are the parent... */ +- it ne +- strne r3, NEGOFF_OFF1 (r2, PID_OFFSET) /* restore the saved PID. */ +- + cmn a1, #4096 + it cc + RETINSTR(cc, lr) +diff --git a/sysdeps/unix/sysv/linux/createthread.c b/sysdeps/unix/sysv/linux/createthread.c +index 6d32cece48..ec86f50814 100644 +--- a/sysdeps/unix/sysv/linux/createthread.c ++++ b/sysdeps/unix/sysv/linux/createthread.c +@@ -128,10 +128,10 @@ create_thread (struct pthread *pd, const struct pthread_attr *attr, + /* The operation failed. We have to kill the thread. + We let the normal cancellation mechanism do the work. */ + ++ pid_t pid = __getpid (); + INTERNAL_SYSCALL_DECL (err2); +- (void) INTERNAL_SYSCALL (tgkill, err2, 3, +- THREAD_GETMEM (THREAD_SELF, pid), +- pd->tid, SIGCANCEL); ++ (void) INTERNAL_SYSCALL_CALL (tgkill, err2, pid, pd->tid, ++ SIGCANCEL); + + return INTERNAL_SYSCALL_ERRNO (res, err); + } +diff --git a/sysdeps/unix/sysv/linux/getcwd.c b/sysdeps/unix/sysv/linux/getcwd.c +index 3f21ae743f..d0b2c38c17 100644 +--- a/sysdeps/unix/sysv/linux/getcwd.c ++++ b/sysdeps/unix/sysv/linux/getcwd.c +@@ -76,7 +76,7 @@ __getcwd (char *buf, size_t size) + int retval; + + retval = INLINE_SYSCALL (getcwd, 2, path, alloc_size); +- if (retval >= 0) ++ if (retval > 0 && path[0] == '/') + { + #ifndef NO_ALLOCATION + if (buf == NULL && size == 0) +@@ -92,10 +92,10 @@ __getcwd (char *buf, size_t size) + return buf; + } + +- /* The system call cannot handle paths longer than a page. +- Neither can the magic symlink in /proc/self. Just use the ++ /* The system call either cannot handle paths longer than a page ++ or can succeed without returning an absolute path. Just use the + generic implementation right away. */ +- if (errno == ENAMETOOLONG) ++ if (retval >= 0 || errno == ENAMETOOLONG) + { + #ifndef NO_ALLOCATION + if (buf == NULL && size == 0) +diff --git a/sysdeps/unix/sysv/linux/getpid.c b/sysdeps/unix/sysv/linux/getpid.c +deleted file mode 100644 +index 1124549326..0000000000 +--- a/sysdeps/unix/sysv/linux/getpid.c ++++ /dev/null +@@ -1,64 +0,0 @@ +-/* Copyright (C) 2003-2016 Free Software Foundation, Inc. +- This file is part of the GNU C Library. +- Contributed by Ulrich Drepper , 2003. +- +- The GNU C Library is free software; you can redistribute it and/or +- modify it under the terms of the GNU Lesser General Public +- License as published by the Free Software Foundation; either +- version 2.1 of the License, or (at your option) any later version. +- +- The GNU C Library is distributed in the hope that it will be useful, +- but WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- Lesser General Public License for more details. +- +- You should have received a copy of the GNU Lesser General Public +- License along with the GNU C Library; if not, see +- . */ +- +-#include +-#include +-#include +- +- +-#if IS_IN (libc) +-static inline __attribute__((always_inline)) pid_t really_getpid (pid_t oldval); +- +-static inline __attribute__((always_inline)) pid_t +-really_getpid (pid_t oldval) +-{ +- if (__glibc_likely (oldval == 0)) +- { +- pid_t selftid = THREAD_GETMEM (THREAD_SELF, tid); +- if (__glibc_likely (selftid != 0)) +- return selftid; +- } +- +- INTERNAL_SYSCALL_DECL (err); +- pid_t result = INTERNAL_SYSCALL (getpid, err, 0); +- +- /* We do not set the PID field in the TID here since we might be +- called from a signal handler while the thread executes fork. */ +- if (oldval == 0) +- THREAD_SETMEM (THREAD_SELF, tid, result); +- return result; +-} +-#endif +- +-pid_t +-__getpid (void) +-{ +-#if !IS_IN (libc) +- INTERNAL_SYSCALL_DECL (err); +- pid_t result = INTERNAL_SYSCALL (getpid, err, 0); +-#else +- pid_t result = THREAD_GETMEM (THREAD_SELF, pid); +- if (__glibc_unlikely (result <= 0)) +- result = really_getpid (result); +-#endif +- return result; +-} +- +-libc_hidden_def (__getpid) +-weak_alias (__getpid, getpid) +-libc_hidden_def (getpid) +diff --git a/sysdeps/unix/sysv/linux/hppa/clone.S b/sysdeps/unix/sysv/linux/hppa/clone.S +index 3d037f1430..25fcd497f7 100644 +--- a/sysdeps/unix/sysv/linux/hppa/clone.S ++++ b/sysdeps/unix/sysv/linux/hppa/clone.S +@@ -132,18 +132,6 @@ ENTRY(__clone) + ldwm -64(%sp), %r4 + + .LthreadStart: +-# define CLONE_VM_BIT 23 /* 0x00000100 */ +- /* Load original clone flags. +- If CLONE_VM was passed, don't modify PID/TID. +- Otherwise store the result of getpid to PID/TID. */ +- ldw -56(%sp), %r26 +- bb,<,n %r26, CLONE_VM_BIT, 1f +- ble 0x100(%sr2, %r0) +- ldi __NR_getpid, %r20 +- mfctl %cr27, %r26 +- stw %ret0, PID_THREAD_OFFSET(%r26) +- stw %ret0, TID_THREAD_OFFSET(%r26) +-1: + /* Load up the arguments. */ + ldw -60(%sp), %arg0 + ldw -64(%sp), %r22 +diff --git a/sysdeps/unix/sysv/linux/hppa/pt-vfork.S b/sysdeps/unix/sysv/linux/hppa/pt-vfork.S +index df532362d2..4684048502 100644 +--- a/sysdeps/unix/sysv/linux/hppa/pt-vfork.S ++++ b/sysdeps/unix/sysv/linux/hppa/pt-vfork.S +@@ -25,26 +25,6 @@ + replaced by a call to `execve'. Return -1 for errors, 0 to the new process, + and the process ID of the new process to the old process. */ + +-/* Load the thread register. +- Load the saved PID value. +- Negate the value. +- Store the temporary PID. */ +-#define SAVE_PID \ +- mfctl %cr27, %r26 ASM_LINE_SEP \ +- ldw PID_THREAD_OFFSET(%r26),%r1 ASM_LINE_SEP \ +- sub %r0,%r1,%r1 ASM_LINE_SEP \ +- stw %r1,PID_THREAD_OFFSET(%r26) ASM_LINE_SEP +-/* If we are the parent... +- Get the thread pointer. +- Load the saved PID. +- Negate the value (got back original) +- Restore the PID. */ +-#define RESTORE_PID \ +- cmpb,=,n %r0,%ret0,.Lthread_start ASM_LINE_SEP \ +- mfctl %cr27, %r26 ASM_LINE_SEP \ +- ldw PID_THREAD_OFFSET(%r26),%r1 ASM_LINE_SEP \ +- sub %r0,%r1,%r1 ASM_LINE_SEP \ +- stw %r1,PID_THREAD_OFFSET(%r26) ASM_LINE_SEP \ + .Lthread_start: ASM_LINE_SEP + + /* r26, r25, r24, r23 are free since vfork has no arguments */ +@@ -58,16 +38,10 @@ ENTRY(__vfork) + copy %r19, %r25 /* parent */ + #endif + +- /* Save the process PID */ +- SAVE_PID +- + /* Syscall saves and restores all register states */ + ble 0x100(%sr2,%r0) + ldi __NR_vfork,%r20 + +- /* Conditionally restore the PID */ +- RESTORE_PID +- + /* Check for error */ + ldi -4096,%r1 + comclr,>>= %r1,%ret0,%r0 /* Note: unsigned compare. */ +diff --git a/sysdeps/unix/sysv/linux/i386/Makefile b/sysdeps/unix/sysv/linux/i386/Makefile +index 71ba61e9d7..6073a9fe04 100644 +--- a/sysdeps/unix/sysv/linux/i386/Makefile ++++ b/sysdeps/unix/sysv/linux/i386/Makefile +@@ -31,6 +31,7 @@ endif + # libpthread uses six-argument inline syscalls. + ifeq ($(subdir),nptl) + libpthread-sysdep_routines += libc-do-syscall ++libpthread-shared-only-routines += libc-do-syscall + endif + + ifeq ($(subdir),resource) +@@ -48,9 +49,11 @@ endif + ifeq ($(subdir),nptl) + # pull in __syscall_error routine + libpthread-routines += sysdep ++libpthread-shared-only-routines += sysdep + endif + + ifeq ($(subdir),rt) + # pull in __syscall_error routine + librt-routines += sysdep ++librt-shared-only-routines += sysdep + endif +diff --git a/sysdeps/unix/sysv/linux/i386/clone.S b/sysdeps/unix/sysv/linux/i386/clone.S +index 25f2a9c340..feae504ce6 100644 +--- a/sysdeps/unix/sysv/linux/i386/clone.S ++++ b/sysdeps/unix/sysv/linux/i386/clone.S +@@ -107,9 +107,6 @@ L(thread_start): + cfi_undefined (eip); + /* Note: %esi is zero. */ + movl %esi,%ebp /* terminate the stack frame */ +- testl $CLONE_VM, %edi +- je L(newpid) +-L(haspid): + call *%ebx + #ifdef PIC + call L(here) +@@ -121,18 +118,6 @@ L(here): + movl $SYS_ify(exit), %eax + ENTER_KERNEL + +- .subsection 2 +-L(newpid): +- movl $SYS_ify(getpid), %eax +- ENTER_KERNEL +-L(nomoregetpid): +- movl %eax, %gs:PID +- movl %eax, %gs:TID +- jmp L(haspid) +- .previous +- cfi_endproc; +- +- cfi_startproc + PSEUDO_END (__clone) + + libc_hidden_def (__clone) +diff --git a/sysdeps/unix/sysv/linux/i386/glob64.c b/sysdeps/unix/sysv/linux/i386/glob64.c +index 802c957d6c..c2cc85741f 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/vfork.S b/sysdeps/unix/sysv/linux/i386/vfork.S +index 7a1d3373bb..a865de2201 100644 +--- a/sysdeps/unix/sysv/linux/i386/vfork.S ++++ b/sysdeps/unix/sysv/linux/i386/vfork.S +@@ -34,17 +34,6 @@ ENTRY (__vfork) + cfi_adjust_cfa_offset (-4) + cfi_register (%eip, %ecx) + +- /* Save the TCB-cached PID away in %edx, and then negate the TCB +- field. But if it's zero, set it to 0x80000000 instead. See +- raise.c for the logic that relies on this value. */ +- movl %gs:PID, %edx +- movl %edx, %eax +- negl %eax +- jne 1f +- movl $0x80000000, %eax +-1: movl %eax, %gs:PID +- +- + /* Stuff the syscall number in EAX and enter into the kernel. */ + movl $SYS_ify (vfork), %eax + int $0x80 +@@ -55,14 +44,6 @@ ENTRY (__vfork) + pushl %ecx + cfi_adjust_cfa_offset (4) + +- /* Restore the original value of the TCB cache of the PID, if we're +- the parent. But in the child (syscall return value equals zero), +- leave things as they are. */ +- testl %eax, %eax +- je 1f +- movl %edx, %gs:PID +-1: +- + cmpl $-4095, %eax + /* Branch forward if it failed. */ + jae SYSCALL_ERROR_LABEL +diff --git a/sysdeps/unix/sysv/linux/ia64/Makefile b/sysdeps/unix/sysv/linux/ia64/Makefile +index 1de62c528a..4d6766db5e 100644 +--- a/sysdeps/unix/sysv/linux/ia64/Makefile ++++ b/sysdeps/unix/sysv/linux/ia64/Makefile +@@ -19,6 +19,7 @@ endif + + ifeq ($(subdir),rt) + librt-routines += rt-sysdep ++librt-shared-only-routines += rt-sysdep + endif + + ifeq ($(subdir),nptl) +diff --git a/sysdeps/unix/sysv/linux/ia64/clone2.S b/sysdeps/unix/sysv/linux/ia64/clone2.S +index b4cfdfc959..e637b6d4a5 100644 +--- a/sysdeps/unix/sysv/linux/ia64/clone2.S ++++ b/sysdeps/unix/sysv/linux/ia64/clone2.S +@@ -67,19 +67,7 @@ ENTRY(__clone2) + (CHILD) mov loc0=gp + (PARENT) ret + ;; +- tbit.nz p6,p0=in3,8 /* CLONE_VM */ +-(p6) br.cond.dptk 1f +- ;; +- mov r15=SYS_ify (getpid) +-(p7) break __BREAK_SYSCALL +- ;; +- add r9=PID,r13 +- add r10=TID,r13 +- ;; +- st4 [r9]=r8 +- st4 [r10]=r8 +- ;; +-1: ld8 out1=[in0],8 /* Retrieve code pointer. */ ++ ld8 out1=[in0],8 /* Retrieve code pointer. */ + mov out0=in4 /* Pass proper argument to fn */ + ;; + ld8 gp=[in0] /* Load function gp. */ +diff --git a/sysdeps/unix/sysv/linux/ia64/vfork.S b/sysdeps/unix/sysv/linux/ia64/vfork.S +index 9154d7c0fd..84bfdd5d8a 100644 +--- a/sysdeps/unix/sysv/linux/ia64/vfork.S ++++ b/sysdeps/unix/sysv/linux/ia64/vfork.S +@@ -33,32 +33,12 @@ ENTRY (__libc_vfork) + .prologue // work around a GAS bug which triggers if + .body // first .prologue is not at the beginning of proc. + alloc r2=ar.pfs,0,0,2,0 +- adds r14=PID,r13 +- ;; +- ld4 r16=[r14] +- ;; +- sub r15=0,r16 +- cmp.eq p6,p0=0,r16 +- ;; +-(p6) movl r15=0x80000000 + mov out0=CLONE_VM+CLONE_VFORK+SIGCHLD + mov out1=0 /* Standard sp value. */ + ;; +- st4 [r14]=r15 + DO_CALL (SYS_ify (clone)) + cmp.eq p6,p0=0,r8 +- adds r14=PID,r13 + (p6) br.cond.dptk 1f +- ;; +- ld4 r15=[r14] +- ;; +- extr.u r16=r15,0,31 +- ;; +- cmp.eq p0,p6=0,r16 +- ;; +-(p6) sub r16=0,r15 +- ;; +- st4 [r14]=r16 + 1: + cmp.eq p6,p0=-1,r10 + (p6) br.cond.spnt.few __syscall_error +diff --git a/sysdeps/unix/sysv/linux/m68k/clone.S b/sysdeps/unix/sysv/linux/m68k/clone.S +index 3a828443dc..630a29209d 100644 +--- a/sysdeps/unix/sysv/linux/m68k/clone.S ++++ b/sysdeps/unix/sysv/linux/m68k/clone.S +@@ -98,19 +98,6 @@ ENTRY (__clone) + cfi_startproc + cfi_undefined (pc) /* Mark end of stack */ + subl %fp, %fp /* terminate the stack frame */ +- /* Check and see if we need to reset the PID. */ +- andl #CLONE_VM, %d1 +- jne 1f +- movel #SYS_ify (getpid), %d0 +- trap #0 +- movel %a0, -(%sp) +- movel %d0, -(%sp) +- bsrl __m68k_read_tp@PLTPC +- movel (%sp)+, %d0 +- movel %d0, PID_OFFSET(%a0) +- movel %d0, TID_OFFSET(%a0) +- movel (%sp)+, %a0 +-1: + jsr (%a0) + movel %d0, %d1 + movel #SYS_ify (exit), %d0 +diff --git a/sysdeps/unix/sysv/linux/m68k/vfork.S b/sysdeps/unix/sysv/linux/m68k/vfork.S +index 1625a7b7a0..e27479361b 100644 +--- a/sysdeps/unix/sysv/linux/m68k/vfork.S ++++ b/sysdeps/unix/sysv/linux/m68k/vfork.S +@@ -28,18 +28,6 @@ + + ENTRY (__vfork) + +- /* Save the TCB-cached PID away in %d1, and then negate the TCB +- field. But if it's zero, set it to 0x80000000 instead. See +- raise.c for the logic that relies on this value. */ +- jbsr __m68k_read_tp@PLTPC +- movel %a0, %a1 +- movel PID_OFFSET(%a1), %d0 +- movel %d0, %d1 +- negl %d0 +- jne 1f +- movel #0x80000000, %d0 +-1: movel %d0, PID_OFFSET(%a1) +- + /* Pop the return PC value into A0. */ + movel %sp@+, %a0 + cfi_adjust_cfa_offset (-4) +@@ -49,14 +37,6 @@ ENTRY (__vfork) + movel #SYS_ify (vfork), %d0 + trap #0 + +- /* Restore the original value of the TCB cache of the PID, if we're +- the parent. But in the child (syscall return value equals zero), +- leave things as they are. */ +- tstl %d0 +- jeq 1f +- movel %d1, PID_OFFSET(%a1) +-1: +- + tstl %d0 + jmi .Lerror /* Branch forward if it failed. */ + +diff --git a/sysdeps/unix/sysv/linux/microblaze/Makefile b/sysdeps/unix/sysv/linux/microblaze/Makefile +index 44a838fa11..d178bc6f34 100644 +--- a/sysdeps/unix/sysv/linux/microblaze/Makefile ++++ b/sysdeps/unix/sysv/linux/microblaze/Makefile +@@ -5,4 +5,5 @@ endif + ifeq ($(subdir),nptl) + # pull in __syscall_error routine + libpthread-routines += sysdep +-endif +\ No newline at end of file ++libpthread-shared-only-routines += sysdep ++endif +diff --git a/sysdeps/unix/sysv/linux/mips/clone.S b/sysdeps/unix/sysv/linux/mips/clone.S +index 39634c5cf0..7ae65ef723 100644 +--- a/sysdeps/unix/sysv/linux/mips/clone.S ++++ b/sysdeps/unix/sysv/linux/mips/clone.S +@@ -130,11 +130,6 @@ L(thread_start): + SAVE_GP (GPOFF) + /* The stackframe has been created on entry of clone(). */ + +- /* Check and see if we need to reset the PID. */ +- and a1,a0,CLONE_VM +- beqz a1,L(restore_pid) +-L(donepid): +- + /* Restore the arg for user's function. */ + PTR_L t9,0(sp) /* Function pointer. */ + PTR_L a0,PTRSIZE(sp) /* Argument pointer. */ +@@ -151,14 +146,6 @@ L(donepid): + jal _exit + #endif + +-L(restore_pid): +- li v0,__NR_getpid +- syscall +- READ_THREAD_POINTER(v1) +- INT_S v0,PID_OFFSET(v1) +- INT_S v0,TID_OFFSET(v1) +- b L(donepid) +- + END(__thread_start) + + libc_hidden_def (__clone) +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/syscalls.list b/sysdeps/unix/sysv/linux/mips/mips64/n64/syscalls.list +index 890a74494a..26ab6d0b75 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/syscalls.list ++++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/syscalls.list +@@ -4,6 +4,8 @@ mmap - mmap b:aniiii __mmap mmap __mmap64 mmap64 + + sync_file_range - sync_file_range Ci:iiii sync_file_range + ++readahead - readahead i:iii __readahead readahead ++ + prlimit EXTRA prlimit64 i:iipp prlimit prlimit64 + + fanotify_mark EXTRA fanotify_mark i:iiiis fanotify_mark +diff --git a/sysdeps/unix/sysv/linux/mips/vfork.S b/sysdeps/unix/sysv/linux/mips/vfork.S +index 1867c8626e..0b9244b7f8 100644 +--- a/sysdeps/unix/sysv/linux/mips/vfork.S ++++ b/sysdeps/unix/sysv/linux/mips/vfork.S +@@ -60,14 +60,6 @@ NESTED(__libc_vfork,FRAMESZ,sp) + PTR_ADDU sp, FRAMESZ + cfi_adjust_cfa_offset (-FRAMESZ) + +- /* Save the PID value. */ +- READ_THREAD_POINTER(v1) /* Get the thread pointer. */ +- lw a2, PID_OFFSET(v1) /* Load the saved PID. */ +- subu a2, $0, a2 /* Negate it. */ +- bnez a2, 1f /* If it was zero... */ +- lui a2, 0x8000 /* use 0x80000000 instead. */ +-1: sw a2, PID_OFFSET(v1) /* Store the temporary PID. */ +- + li a0, 0x4112 /* CLONE_VM | CLONE_VFORK | SIGCHLD */ + move a1, sp + +@@ -75,17 +67,6 @@ NESTED(__libc_vfork,FRAMESZ,sp) + li v0,__NR_clone + syscall + +- /* Restore the old PID value in the parent. */ +- beqz v0, 1f /* If we are the parent... */ +- READ_THREAD_POINTER(v1) /* Get the thread pointer. */ +- lw a2, PID_OFFSET(v1) /* Load the saved PID. */ +- subu a2, $0, a2 /* Re-negate it. */ +- lui a0, 0x8000 /* Load 0x80000000... */ +- bne a2, a0, 2f /* ... compare against it... */ +- li a2, 0 /* ... use 0 instead. */ +-2: sw a2, PID_OFFSET(v1) /* Restore the PID. */ +-1: +- + cfi_remember_state + bnez a3,L(error) + +diff --git a/sysdeps/unix/sysv/linux/nios2/clone.S b/sysdeps/unix/sysv/linux/nios2/clone.S +index 30b6e4a6c8..c9fa00f94c 100644 +--- a/sysdeps/unix/sysv/linux/nios2/clone.S ++++ b/sysdeps/unix/sysv/linux/nios2/clone.S +@@ -68,14 +68,6 @@ thread_start: + cfi_startproc + cfi_undefined (ra) + +- /* We expect the argument registers to be preserved across system +- calls and across task cloning, so flags should be in r4 here. */ +- andi r2, r4, CLONE_VM +- bne r2, zero, 2f +- DO_CALL (getpid, 0) +- stw r2, PID_OFFSET(r23) +- stw r2, TID_OFFSET(r23) +-2: + ldw r5, 4(sp) /* Function pointer. */ + ldw r4, 0(sp) /* Argument pointer. */ + addi sp, sp, 8 +diff --git a/sysdeps/unix/sysv/linux/nios2/vfork.S b/sysdeps/unix/sysv/linux/nios2/vfork.S +index c1bb9c7134..8997269199 100644 +--- a/sysdeps/unix/sysv/linux/nios2/vfork.S ++++ b/sysdeps/unix/sysv/linux/nios2/vfork.S +@@ -21,20 +21,10 @@ + + ENTRY(__vfork) + +- ldw r6, PID_OFFSET(r23) +- sub r7, zero, r6 +- bne r7, zero, 2f +- movhi r7, %hi(0x80000000) +-2: +- stw r7, PID_OFFSET(r23) +- + movi r4, 0x4111 /* (CLONE_VM | CLONE_VFORK | SIGCHLD) */ + mov r5, zero + DO_CALL (clone, 2) + +- beq r2, zero, 1f +- stw r6, PID_OFFSET(r23) +-1: + bne r7, zero, SYSCALL_ERROR_LABEL + ret + +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/powerpc/Makefile b/sysdeps/unix/sysv/linux/powerpc/Makefile +index c89ed9ec7d..2cfb46eca3 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/Makefile ++++ b/sysdeps/unix/sysv/linux/powerpc/Makefile +@@ -8,6 +8,7 @@ abi-64-v2-condition := __WORDSIZE == 64 && _CALL_ELF == 2 + + ifeq ($(subdir),rt) + librt-routines += rt-sysdep ++librt-shared-only-routines += rt-sysdep + endif + + ifeq ($(subdir),stdlib) +@@ -34,4 +35,5 @@ ifeq ($(subdir),nptl) + libpthread-routines += sysdep + libpthread-sysdep_routines += elision-lock elision-unlock elision-timed \ + elision-trylock ++libpthread-shared-only-routines += sysdep + endif +diff --git a/sysdeps/unix/sysv/linux/powerpc/elision-lock.c b/sysdeps/unix/sysv/linux/powerpc/elision-lock.c +index dd1e4c3b17..7dd3d835b6 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/elision-lock.c ++++ b/sysdeps/unix/sysv/linux/powerpc/elision-lock.c +@@ -45,7 +45,9 @@ + int + __lll_lock_elision (int *lock, short *adapt_count, EXTRAARG int pshared) + { +- if (*adapt_count > 0) ++ /* adapt_count is accessed concurrently but is just a hint. Thus, ++ use atomic accesses but relaxed MO is sufficient. */ ++ if (atomic_load_relaxed (adapt_count) > 0) + { + goto use_lock; + } +@@ -67,7 +69,8 @@ __lll_lock_elision (int *lock, short *adapt_count, EXTRAARG int pshared) + if (_TEXASRU_FAILURE_PERSISTENT (__builtin_get_texasru ())) + { + if (aconf.skip_lock_internal_abort > 0) +- *adapt_count = aconf.skip_lock_internal_abort; ++ atomic_store_relaxed (adapt_count, ++ aconf.skip_lock_internal_abort); + goto use_lock; + } + } +@@ -75,7 +78,8 @@ __lll_lock_elision (int *lock, short *adapt_count, EXTRAARG int pshared) + + /* Fall back to locks for a bit if retries have been exhausted */ + if (aconf.try_tbegin > 0 && aconf.skip_lock_out_of_tbegin_retries > 0) +- *adapt_count = aconf.skip_lock_out_of_tbegin_retries; ++ atomic_store_relaxed (adapt_count, ++ aconf.skip_lock_out_of_tbegin_retries); + + use_lock: + return LLL_LOCK ((*lock), pshared); +diff --git a/sysdeps/unix/sysv/linux/powerpc/elision-trylock.c b/sysdeps/unix/sysv/linux/powerpc/elision-trylock.c +index 0807a6a432..606185670d 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/elision-trylock.c ++++ b/sysdeps/unix/sysv/linux/powerpc/elision-trylock.c +@@ -34,7 +34,7 @@ __lll_trylock_elision (int *futex, short *adapt_count) + __libc_tabort (_ABORT_NESTED_TRYLOCK); + + /* Only try a transaction if it's worth it. */ +- if (*adapt_count > 0) ++ if (atomic_load_relaxed (adapt_count) > 0) + { + goto use_lock; + } +@@ -49,7 +49,7 @@ __lll_trylock_elision (int *futex, short *adapt_count) + __libc_tend (0); + + if (aconf.skip_lock_busy > 0) +- *adapt_count = aconf.skip_lock_busy; ++ atomic_store_relaxed (adapt_count, aconf.skip_lock_busy); + } + else + { +@@ -59,7 +59,8 @@ __lll_trylock_elision (int *futex, short *adapt_count) + result in another failure. Use normal locking now and + for the next couple of calls. */ + if (aconf.skip_trylock_internal_abort > 0) +- *adapt_count = aconf.skip_trylock_internal_abort; ++ atomic_store_relaxed (adapt_count, ++ aconf.skip_trylock_internal_abort); + } + } + +diff --git a/sysdeps/unix/sysv/linux/powerpc/elision-unlock.c b/sysdeps/unix/sysv/linux/powerpc/elision-unlock.c +index 43c5a67df2..51d7018e4c 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/elision-unlock.c ++++ b/sysdeps/unix/sysv/linux/powerpc/elision-unlock.c +@@ -28,13 +28,16 @@ __lll_unlock_elision (int *lock, short *adapt_count, int pshared) + __libc_tend (0); + else + { +- lll_unlock ((*lock), pshared); ++ /* Update adapt_count in the critical section to prevent a ++ write-after-destroy error as mentioned in BZ 20822. The ++ following update of adapt_count has to be contained within ++ the critical region of the fall-back lock in order to not violate ++ the mutex destruction requirements. */ ++ short __tmp = atomic_load_relaxed (adapt_count); ++ if (__tmp > 0) ++ atomic_store_relaxed (adapt_count, __tmp - 1); + +- /* Update the adapt count AFTER completing the critical section. +- Doing this here prevents unneeded stalling when entering +- a critical section. Saving about 8% runtime on P8. */ +- if (*adapt_count > 0) +- (*adapt_count)--; ++ lll_unlock ((*lock), pshared); + } + return 0; + } +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/clone.S b/sysdeps/unix/sysv/linux/powerpc/powerpc32/clone.S +index bebadbfbb9..49fe01ecde 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/clone.S ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/clone.S +@@ -76,15 +76,6 @@ ENTRY (__clone) + crandc cr1*4+eq,cr1*4+eq,cr0*4+so + bne- cr1,L(parent) /* The '-' is to minimise the race. */ + +- /* If CLONE_VM is set do not update the pid/tid field. */ +- andi. r0,r28,CLONE_VM +- bne+ cr0,L(oldpid) +- +- DO_CALL(SYS_ify(getpid)) +- stw r3,TID(r2) +- stw r3,PID(r2) +-L(oldpid): +- + /* Call procedure. */ + mtctr r30 + mr r3,r31 +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S b/sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S +index edbc7de1e6..0a724953a4 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S +@@ -27,34 +27,8 @@ + + ENTRY (__vfork) + +- /* Load the TCB-cached PID value and negates it. If It it is zero +- sets it to 0x800000. And then sets its value again on TCB field. +- See raise.c for the logic that relies on this value. */ +- +- lwz r0,PID(r2) +- cmpwi cr0,r0,0 +- neg r0,r0 +- bne- cr0,1f +- lis r0,0x8000 +-1: stw r0,PID(r2) +- + DO_CALL (SYS_ify (vfork)) + +- cmpwi cr1,r3,0 +- beqlr- 1 +- +- /* Restore the original value of the TCB cache of the PID, if we're +- the parent. But in the child (syscall return value equals zero), +- leave things as they are. */ +- lwz r0,PID(r2) +- /* Cannot use clrlwi. here, because cr0 needs to be preserved +- until PSEUDO_RET. */ +- clrlwi r4,r0,1 +- cmpwi cr1,r4,0 +- beq- cr1,1f +- neg r4,r0 +-1: stw r4,PID(r2) +- + PSEUDO_RET + + PSEUDO_END (__vfork) +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S b/sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S +index 7c59b9b4e9..d8604f6731 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S +@@ -78,15 +78,6 @@ ENTRY (__clone) + crandc cr1*4+eq,cr1*4+eq,cr0*4+so + bne- cr1,L(parent) /* The '-' is to minimise the race. */ + +- /* If CLONE_VM is set do not update the pid/tid field. */ +- rldicl. r0,r29,56,63 /* flags & CLONE_VM. */ +- bne+ cr0,L(oldpid) +- +- DO_CALL(SYS_ify(getpid)) +- stw r3,TID(r13) +- stw r3,PID(r13) +-L(oldpid): +- + std r2,FRAME_TOC_SAVE(r1) + /* Call procedure. */ + PPC64_LOAD_FUNCPTR r30 +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/vfork.S b/sysdeps/unix/sysv/linux/powerpc/powerpc64/vfork.S +index 3083ab7b3c..6b4cf432c1 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/vfork.S ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/vfork.S +@@ -28,31 +28,8 @@ + ENTRY (__vfork) + CALL_MCOUNT 0 + +- /* Load the TCB-cached PID value and negates it. If It it is zero +- sets it to 0x800000. And then sets its value again on TCB field. +- See raise.c for the logic that relies on this value. */ +- lwz r0,PID(r13) +- cmpwi cr0,r0,0 +- neg r0,r0 +- bne- cr0,1f +- lis r0,0x8000 +-1: stw r0,PID(r13) +- + DO_CALL (SYS_ify (vfork)) + +- cmpwi cr1,r3,0 +- beqlr- 1 +- +- /* Restore the original value of the TCB cache of the PID, if we're +- the parent. But in the child (syscall return value equals zero), +- leave things as they are. */ +- lwz r0,PID(r13) +- clrlwi r4,r0,1 +- cmpwi cr1,r4,0 +- beq- cr1,1f +- neg r4,r0 +-1: stw r4,PID(r13) +- + PSEUDO_RET + + PSEUDO_END (__vfork) +diff --git a/sysdeps/unix/sysv/linux/pread.c b/sysdeps/unix/sysv/linux/pread.c +index 1bcff64781..46d974d952 100644 +--- a/sysdeps/unix/sysv/linux/pread.c ++++ b/sysdeps/unix/sysv/linux/pread.c +@@ -28,8 +28,7 @@ + ssize_t + __libc_pread (int fd, void *buf, size_t count, off_t offset) + { +- return SYSCALL_CANCEL (pread, fd, buf, count, +- __ALIGNMENT_ARG SYSCALL_LL (offset)); ++ return SYSCALL_CANCEL (pread, fd, buf, count, SYSCALL_LL_PRW (offset)); + } + + strong_alias (__libc_pread, __pread) +diff --git a/sysdeps/unix/sysv/linux/pread64.c b/sysdeps/unix/sysv/linux/pread64.c +index 58c6aeb541..f51beae77a 100644 +--- a/sysdeps/unix/sysv/linux/pread64.c ++++ b/sysdeps/unix/sysv/linux/pread64.c +@@ -26,8 +26,7 @@ + ssize_t + __libc_pread64 (int fd, void *buf, size_t count, off64_t offset) + { +- return SYSCALL_CANCEL (pread64, fd, buf, count, +- __ALIGNMENT_ARG SYSCALL_LL64 (offset)); ++ return SYSCALL_CANCEL (pread64, fd, buf, count, SYSCALL_LL64_PRW (offset)); + } + + weak_alias (__libc_pread64, __pread64) +diff --git a/sysdeps/unix/sysv/linux/pthread-pids.h b/sysdeps/unix/sysv/linux/pthread-pids.h +index d42bba03cf..618a5b1b9f 100644 +--- a/sysdeps/unix/sysv/linux/pthread-pids.h ++++ b/sysdeps/unix/sysv/linux/pthread-pids.h +@@ -26,5 +26,5 @@ static inline void + __pthread_initialize_pids (struct pthread *pd) + { + INTERNAL_SYSCALL_DECL (err); +- pd->pid = pd->tid = INTERNAL_SYSCALL (set_tid_address, err, 1, &pd->tid); ++ pd->tid = INTERNAL_SYSCALL_CALL (set_tid_address, err, &pd->tid); + } +diff --git a/sysdeps/unix/sysv/linux/pthread_kill.c b/sysdeps/unix/sysv/linux/pthread_kill.c +index bcb3009675..cc109973cc 100644 +--- a/sysdeps/unix/sysv/linux/pthread_kill.c ++++ b/sysdeps/unix/sysv/linux/pthread_kill.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + + + int +@@ -49,15 +50,9 @@ __pthread_kill (pthread_t threadid, int signo) + /* We have a special syscall to do the work. */ + INTERNAL_SYSCALL_DECL (err); + +- /* One comment: The PID field in the TCB can temporarily be changed +- (in fork). But this must not affect this code here. Since this +- function would have to be called while the thread is executing +- fork, it would have to happen in a signal handler. But this is +- no allowed, pthread_kill is not guaranteed to be async-safe. */ +- int val; +- val = INTERNAL_SYSCALL (tgkill, err, 3, THREAD_GETMEM (THREAD_SELF, pid), +- tid, signo); ++ pid_t pid = __getpid (); + ++ int val = INTERNAL_SYSCALL_CALL (tgkill, err, pid, tid, signo); + return (INTERNAL_SYSCALL_ERROR_P (val, err) + ? INTERNAL_SYSCALL_ERRNO (val, err) : 0); + } +diff --git a/sysdeps/unix/sysv/linux/pthread_sigqueue.c b/sysdeps/unix/sysv/linux/pthread_sigqueue.c +index 7694d5467c..e393e0bd73 100644 +--- a/sysdeps/unix/sysv/linux/pthread_sigqueue.c ++++ b/sysdeps/unix/sysv/linux/pthread_sigqueue.c +@@ -49,27 +49,22 @@ pthread_sigqueue (pthread_t threadid, int signo, const union sigval value) + if (signo == SIGCANCEL || signo == SIGTIMER || signo == SIGSETXID) + return EINVAL; + ++ pid_t pid = getpid (); ++ + /* Set up the siginfo_t structure. */ + siginfo_t info; + memset (&info, '\0', sizeof (siginfo_t)); + info.si_signo = signo; + info.si_code = SI_QUEUE; +- info.si_pid = THREAD_GETMEM (THREAD_SELF, pid); ++ info.si_pid = pid; + info.si_uid = getuid (); + info.si_value = value; + + /* We have a special syscall to do the work. */ + INTERNAL_SYSCALL_DECL (err); + +- /* One comment: The PID field in the TCB can temporarily be changed +- (in fork). But this must not affect this code here. Since this +- function would have to be called while the thread is executing +- fork, it would have to happen in a signal handler. But this is +- no allowed, pthread_sigqueue is not guaranteed to be async-safe. */ +- int val = INTERNAL_SYSCALL (rt_tgsigqueueinfo, err, 4, +- THREAD_GETMEM (THREAD_SELF, pid), +- tid, signo, &info); +- ++ int val = INTERNAL_SYSCALL_CALL (rt_tgsigqueueinfo, err, pid, tid, signo, ++ &info); + return (INTERNAL_SYSCALL_ERROR_P (val, err) + ? INTERNAL_SYSCALL_ERRNO (val, err) : 0); + #else +diff --git a/sysdeps/unix/sysv/linux/pwrite.c b/sysdeps/unix/sysv/linux/pwrite.c +index 9c502beac1..1371df8a60 100644 +--- a/sysdeps/unix/sysv/linux/pwrite.c ++++ b/sysdeps/unix/sysv/linux/pwrite.c +@@ -28,8 +28,7 @@ + ssize_t + __libc_pwrite (int fd, const void *buf, size_t count, off_t offset) + { +- return SYSCALL_CANCEL (pwrite, fd, buf, count, +- __ALIGNMENT_ARG SYSCALL_LL (offset)); ++ return SYSCALL_CANCEL (pwrite, fd, buf, count, SYSCALL_LL_PRW (offset)); + } + + strong_alias (__libc_pwrite, __pwrite) +diff --git a/sysdeps/unix/sysv/linux/pwrite64.c b/sysdeps/unix/sysv/linux/pwrite64.c +index b49e6bc286..22f1f05a44 100644 +--- a/sysdeps/unix/sysv/linux/pwrite64.c ++++ b/sysdeps/unix/sysv/linux/pwrite64.c +@@ -26,8 +26,7 @@ + ssize_t + __libc_pwrite64 (int fd, const void *buf, size_t count, off64_t offset) + { +- return SYSCALL_CANCEL (pwrite64, fd, buf, count, +- __ALIGNMENT_ARG SYSCALL_LL64 (offset)); ++ return SYSCALL_CANCEL (pwrite64, fd, buf, count, SYSCALL_LL64_PRW (offset)); + } + weak_alias (__libc_pwrite64, __pwrite64) + libc_hidden_weak (__pwrite64) +diff --git a/sysdeps/unix/sysv/linux/raise.c b/sysdeps/unix/sysv/linux/raise.c +index 470033e83d..49bb7cb0d4 100644 +--- a/sysdeps/unix/sysv/linux/raise.c ++++ b/sysdeps/unix/sysv/linux/raise.c +@@ -26,13 +26,6 @@ + int + raise (int sig) + { +- /* raise is an async-safe function so it could be called while the +- fork/vfork function temporarily invalidated the PID field. To avoid +- relying on cached value we block all user-defined signal handler +- (which might call fork/vfork) and issue the getpid and gettid +- syscalls directly. */ +- +- + /* rt_sigprocmask may fail if: + + 1. sigsetsize != sizeof (sigset_t) (EINVAL) +diff --git a/sysdeps/unix/sysv/linux/s390/Makefile b/sysdeps/unix/sysv/linux/s390/Makefile +index 497ffd566c..f8ed013e9e 100644 +--- a/sysdeps/unix/sysv/linux/s390/Makefile ++++ b/sysdeps/unix/sysv/linux/s390/Makefile +@@ -6,6 +6,7 @@ abi-64-condition := __WORDSIZE == 64 + + ifeq ($(subdir),rt) + librt-routines += rt-sysdep ++librt-shared-only-routines += rt-sysdep + endif + + ifeq ($(subdir),stdlib) +diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/clone.S b/sysdeps/unix/sysv/linux/s390/s390-32/clone.S +index 2f8fa0b840..b1de1480d1 100644 +--- a/sysdeps/unix/sysv/linux/s390/s390-32/clone.S ++++ b/sysdeps/unix/sysv/linux/s390/s390-32/clone.S +@@ -54,13 +54,6 @@ error: + PSEUDO_END (__clone) + + thread_start: +- tml %r3,256 /* CLONE_VM == 0x00000100 */ +- jne 1f +- svc SYS_ify(getpid) +- ear %r3,%a0 +- st %r2,PID(%r3) +- st %r2,TID(%r3) +-1: + /* fn is in gpr 1, arg in gpr 0 */ + lr %r2,%r0 /* set first parameter to void *arg */ + ahi %r15,-96 /* make room on the stack for the save area */ +diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/vfork.S b/sysdeps/unix/sysv/linux/s390/s390-32/vfork.S +index b7588ebd7c..cc60e139ba 100644 +--- a/sysdeps/unix/sysv/linux/s390/s390-32/vfork.S ++++ b/sysdeps/unix/sysv/linux/s390/s390-32/vfork.S +@@ -28,21 +28,9 @@ + and the process ID of the new process to the old process. */ + + ENTRY (__libc_vfork) +- ear %r4,%a0 +- lhi %r1,1 +- icm %r3,15,PID(%r4) +- sll %r1,31 +- je 1f +- lcr %r1,%r3 +-1: st %r1,PID(%r4) +- + /* Do vfork system call. */ + svc SYS_ify (vfork) + +- ltr %r2,%r2 +- je 1f +- st %r3,PID(%r4) +-1: + /* Check for error. */ + lhi %r4,-4095 + clr %r2,%r4 +diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/clone.S b/sysdeps/unix/sysv/linux/s390/s390-64/clone.S +index fb816922ca..29606acf03 100644 +--- a/sysdeps/unix/sysv/linux/s390/s390-64/clone.S ++++ b/sysdeps/unix/sysv/linux/s390/s390-64/clone.S +@@ -55,15 +55,6 @@ error: + PSEUDO_END (__clone) + + thread_start: +- tmll %r3,256 /* CLONE_VM == 0x00000100 */ +- jne 1f +- svc SYS_ify(getpid) +- ear %r3,%a0 +- sllg %r3,%r3,32 +- ear %r3,%a1 +- st %r2,PID(%r3) +- st %r2,TID(%r3) +-1: + /* fn is in gpr 1, arg in gpr 0 */ + lgr %r2,%r0 /* set first parameter to void *arg */ + aghi %r15,-160 /* make room on the stack for the save area */ +diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/vfork.S b/sysdeps/unix/sysv/linux/s390/s390-64/vfork.S +index 0bd2161381..b9a813f2cc 100644 +--- a/sysdeps/unix/sysv/linux/s390/s390-64/vfork.S ++++ b/sysdeps/unix/sysv/linux/s390/s390-64/vfork.S +@@ -28,22 +28,9 @@ + and the process ID of the new process to the old process. */ + + ENTRY (__libc_vfork) +- ear %r4,%a0 +- sllg %r4,%r4,32 +- ear %r4,%a1 +- icm %r3,15,PID(%r4) +- llilh %r1,32768 +- je 1f +- lcr %r1,%r3 +-1: st %r1,PID(%r4) +- + /* Do vfork system call. */ + svc SYS_ify (vfork) + +- ltgr %r2,%r2 +- je 1f +- st %r3,PID(%r4) +-1: + /* Check for error. */ + lghi %r4,-4095 + clgr %r2,%r4 +diff --git a/sysdeps/unix/sysv/linux/sh/clone.S b/sysdeps/unix/sysv/linux/sh/clone.S +index 4cd7df117c..ce7cddcb19 100644 +--- a/sysdeps/unix/sysv/linux/sh/clone.S ++++ b/sysdeps/unix/sysv/linux/sh/clone.S +@@ -66,23 +66,7 @@ ENTRY(__clone) + 2: + /* terminate the stack frame */ + mov #0, r14 +- mov r4, r0 +- shlr8 r0 +- tst #1, r0 // CLONE_VM = (1 << 8) +- bf/s 4f +- mov r4, r0 +- /* new pid */ +- mov #+SYS_ify(getpid), r3 +- trapa #0x15 +-3: +- stc gbr, r1 +- mov.w .Lpidoff, r2 +- add r1, r2 +- mov.l r0, @r2 +- mov.w .Ltidoff, r2 +- add r1, r2 +- mov.l r0, @r2 +-4: ++ + /* thread starts */ + mov.l @r15, r1 + jsr @r1 +@@ -113,10 +97,6 @@ ENTRY(__clone) + .long _GLOBAL_OFFSET_TABLE_ + .L3: + .long PLTJMP(C_SYMBOL_NAME(_exit)) +-.Lpidoff: +- .word PID - TLS_PRE_TCB_SIZE +-.Ltidoff: +- .word TID - TLS_PRE_TCB_SIZE + PSEUDO_END (__clone) + + libc_hidden_def (__clone) +diff --git a/sysdeps/unix/sysv/linux/sh/kernel-features.h b/sysdeps/unix/sysv/linux/sh/kernel-features.h +index ad05fc39e1..c5240fafbd 100644 +--- a/sysdeps/unix/sysv/linux/sh/kernel-features.h ++++ b/sysdeps/unix/sysv/linux/sh/kernel-features.h +@@ -44,3 +44,8 @@ + + /* SH does not have a 64-bit inode field. */ + #undef __ASSUME_ST_INO_64_BIT ++ ++/* SH4 ABI does not really require argument alignment for 64-bits, but ++ the kernel interface for p{read,write}64 adds a dummy long argument ++ before the offset. */ ++#define __ASSUME_PRW_DUMMY_ARG 1 +diff --git a/sysdeps/unix/sysv/linux/sh/pwrite.c b/sysdeps/unix/sysv/linux/sh/pwrite.c +deleted file mode 100644 +index 391ed5e17b..0000000000 +--- a/sysdeps/unix/sysv/linux/sh/pwrite.c ++++ /dev/null +@@ -1,23 +0,0 @@ +-/* Copyright (C) 1997-2016 Free Software Foundation, Inc. +- This file is part of the GNU C Library. +- Contributed by Ulrich Drepper , 1997. +- +- 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 +- . */ +- +-/* SH4 ABI does not really require argument alignment for 64-bits, but +- the kernel interface for pwrite adds a dummy long argument before the +- offset. */ +-#define __ALIGNMENT_ARG +-#include +diff --git a/sysdeps/unix/sysv/linux/sh/sh3/ucontext_i.sym b/sysdeps/unix/sysv/linux/sh/sh3/ucontext_i.sym +index 17397c5511..25f914a93b 100644 +--- a/sysdeps/unix/sysv/linux/sh/sh3/ucontext_i.sym ++++ b/sysdeps/unix/sysv/linux/sh/sh3/ucontext_i.sym +@@ -13,22 +13,22 @@ SIG_SETMASK + oLINK ucontext (uc_link) + oSS_SP ucontext (uc_stack.ss_sp) + oSS_SIZE ucontext (uc_stack.ss_size) +-oR0 mcontext (gregs[R0]) +-oR1 mcontext (gregs[R1]) +-oR2 mcontext (gregs[R2]) +-oR3 mcontext (gregs[R3]) +-oR4 mcontext (gregs[R4]) +-oR5 mcontext (gregs[R5]) +-oR6 mcontext (gregs[R6]) +-oR7 mcontext (gregs[R7]) +-oR8 mcontext (gregs[R8]) +-oR9 mcontext (gregs[R9]) +-oR10 mcontext (gregs[R10]) +-oR11 mcontext (gregs[R11]) +-oR12 mcontext (gregs[R12]) +-oR13 mcontext (gregs[R13]) +-oR14 mcontext (gregs[R14]) +-oR15 mcontext (gregs[R15]) ++oR0 mcontext (gregs[REG_R0]) ++oR1 mcontext (gregs[REG_R1]) ++oR2 mcontext (gregs[REG_R2]) ++oR3 mcontext (gregs[REG_R3]) ++oR4 mcontext (gregs[REG_R4]) ++oR5 mcontext (gregs[REG_R5]) ++oR6 mcontext (gregs[REG_R6]) ++oR7 mcontext (gregs[REG_R7]) ++oR8 mcontext (gregs[REG_R8]) ++oR9 mcontext (gregs[REG_R9]) ++oR10 mcontext (gregs[REG_R10]) ++oR11 mcontext (gregs[REG_R11]) ++oR12 mcontext (gregs[REG_R12]) ++oR13 mcontext (gregs[REG_R13]) ++oR14 mcontext (gregs[REG_R14]) ++oR15 mcontext (gregs[REG_R15]) + oPC mcontext (pc) + oPR mcontext (pr) + oSR mcontext (sr) +diff --git a/sysdeps/unix/sysv/linux/sh/sh4/ucontext_i.sym b/sysdeps/unix/sysv/linux/sh/sh4/ucontext_i.sym +index 65633fbcf4..130f60cd96 100644 +--- a/sysdeps/unix/sysv/linux/sh/sh4/ucontext_i.sym ++++ b/sysdeps/unix/sysv/linux/sh/sh4/ucontext_i.sym +@@ -13,22 +13,22 @@ SIG_SETMASK + oLINK ucontext (uc_link) + oSS_SP ucontext (uc_stack.ss_sp) + oSS_SIZE ucontext (uc_stack.ss_size) +-oR0 mcontext (gregs[R0]) +-oR1 mcontext (gregs[R1]) +-oR2 mcontext (gregs[R2]) +-oR3 mcontext (gregs[R3]) +-oR4 mcontext (gregs[R4]) +-oR5 mcontext (gregs[R5]) +-oR6 mcontext (gregs[R6]) +-oR7 mcontext (gregs[R7]) +-oR8 mcontext (gregs[R8]) +-oR9 mcontext (gregs[R9]) +-oR10 mcontext (gregs[R10]) +-oR11 mcontext (gregs[R11]) +-oR12 mcontext (gregs[R12]) +-oR13 mcontext (gregs[R13]) +-oR14 mcontext (gregs[R14]) +-oR15 mcontext (gregs[R15]) ++oR0 mcontext (gregs[REG_R0]) ++oR1 mcontext (gregs[REG_R1]) ++oR2 mcontext (gregs[REG_R2]) ++oR3 mcontext (gregs[REG_R3]) ++oR4 mcontext (gregs[REG_R4]) ++oR5 mcontext (gregs[REG_R5]) ++oR6 mcontext (gregs[REG_R6]) ++oR7 mcontext (gregs[REG_R7]) ++oR8 mcontext (gregs[REG_R8]) ++oR9 mcontext (gregs[REG_R9]) ++oR10 mcontext (gregs[REG_R10]) ++oR11 mcontext (gregs[REG_R11]) ++oR12 mcontext (gregs[REG_R12]) ++oR13 mcontext (gregs[REG_R13]) ++oR14 mcontext (gregs[REG_R14]) ++oR15 mcontext (gregs[REG_R15]) + oPC mcontext (pc) + oPR mcontext (pr) + oSR mcontext (sr) +diff --git a/sysdeps/unix/sysv/linux/sh/sys/ucontext.h b/sysdeps/unix/sysv/linux/sh/sys/ucontext.h +index ab9a7e66bf..037fbb73e8 100644 +--- a/sysdeps/unix/sysv/linux/sh/sys/ucontext.h ++++ b/sysdeps/unix/sysv/linux/sh/sys/ucontext.h +@@ -31,49 +31,47 @@ + typedef int greg_t; + + /* Number of general registers. */ +-#define NGPREG 16 ++#define NGREG 16 + + /* Container for all general registers. */ +-typedef greg_t gregset_t[NGPREG]; ++typedef greg_t gregset_t[NGREG]; + +-#ifdef __USE_GNU + /* Number of each register is the `gregset_t' array. */ + enum + { +- R0 = 0, +-#define R0 R0 +- R1 = 1, +-#define R1 R1 +- R2 = 2, +-#define R2 R2 +- R3 = 3, +-#define R3 R3 +- R4 = 4, +-#define R4 R4 +- R5 = 5, +-#define R5 R5 +- R6 = 6, +-#define R6 R6 +- R7 = 7, +-#define R7 R7 +- R8 = 8, +-#define R8 R8 +- R9 = 9, +-#define R9 R9 +- R10 = 10, +-#define R10 R10 +- R11 = 11, +-#define R11 R11 +- R12 = 12, +-#define R12 R12 +- R13 = 13, +-#define R13 R13 +- R14 = 14, +-#define R14 R14 +- R15 = 15, +-#define R15 R15 ++ REG_R0 = 0, ++#define REG_R0 REG_R0 ++ REG_R1 = 1, ++#define REG_R1 REG_R1 ++ REG_R2 = 2, ++#define REG_R2 REG_R2 ++ REG_R3 = 3, ++#define REG_R3 REG_R3 ++ REG_R4 = 4, ++#define REG_R4 REG_R4 ++ REG_R5 = 5, ++#define REG_R5 REG_R5 ++ REG_R6 = 6, ++#define REG_R6 REG_R6 ++ REG_R7 = 7, ++#define REG_R7 REG_R7 ++ REG_R8 = 8, ++#define REG_R8 REG_R8 ++ REG_R9 = 9, ++#define REG_R9 REG_R9 ++ REG_R10 = 10, ++#define REG_R10 REG_R10 ++ REG_R11 = 11, ++#define REG_R11 REG_R11 ++ REG_R12 = 12, ++#define REG_R12 REG_R12 ++ REG_R13 = 13, ++#define REG_R13 REG_R13 ++ REG_R14 = 14, ++#define REG_R14 REG_R14 ++ REG_R15 = 15, ++#define REG_R15 REG_R15 + }; +-#endif + + #if (defined(__SH4__) || defined(__SH4A__)) + typedef int freg_t; +diff --git a/sysdeps/unix/sysv/linux/sh/vfork.S b/sysdeps/unix/sysv/linux/sh/vfork.S +index 6895bc5491..df559cb439 100644 +--- a/sysdeps/unix/sysv/linux/sh/vfork.S ++++ b/sysdeps/unix/sysv/linux/sh/vfork.S +@@ -26,30 +26,11 @@ + and the process ID of the new process to the old process. */ + + ENTRY (__libc_vfork) +- /* Save the PID value. */ +- stc gbr, r2 +- mov.w .L2, r0 +- mov.l @(r0,r2), r4 +- neg r4, r1 +- tst r1, r1 +- bf 1f +- mov #1, r1 +- rotr r1 +-1: +- mov.l r1, @(r0,r2) + + mov.w .L1, r3 + trapa #0x10 + mov r0, r1 + +- /* Restore the old PID value in the parent. */ +- tst r0, r0 +- bt.s 2f +- stc gbr, r2 +- mov.w .L2, r0 +- mov.l r4, @(r0,r2) +- mov r1, r0 +-2: + mov #-12, r2 + shad r2, r1 + not r1, r1 // r1=0 means r0 = -1 to -4095 +@@ -61,8 +42,6 @@ ENTRY (__libc_vfork) + nop + .L1: + .word __NR_vfork +-.L2: +- .word PID - TLS_PRE_TCB_SIZE + .align 2 + PSEUDO_END (__libc_vfork) + +diff --git a/sysdeps/unix/sysv/linux/sparc/Makefile b/sysdeps/unix/sysv/linux/sparc/Makefile +index e67aecf8f0..a67d199eb5 100644 +--- a/sysdeps/unix/sysv/linux/sparc/Makefile ++++ b/sysdeps/unix/sysv/linux/sparc/Makefile +@@ -6,6 +6,7 @@ abi-64-condition := __WORDSIZE == 64 + + ifeq ($(subdir),rt) + librt-routines += rt-sysdep ++librt-shared-only-routines += rt-sysdep + endif + + ifeq ($(subdir),sysvipc) +@@ -15,4 +16,5 @@ endif + ifeq ($(subdir),nptl) + # pull in __syscall_error routine + libpthread-routines += sysdep ++libpthread-shared-only-routines += sysdep + endif +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S b/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S +index d6c92f6133..0456a0d16e 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S ++++ b/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S +@@ -79,13 +79,6 @@ END(__clone) + + .type __thread_start,@function + __thread_start: +- andcc %g4, CLONE_VM, %g0 +- bne 1f +- set __NR_getpid,%g1 +- ta 0x10 +- st %o0,[%g7 + PID] +- st %o0,[%g7 + TID] +-1: + mov %g0, %fp /* terminate backtrace */ + call %g2 + mov %g3,%o0 +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S b/sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S +index 0d0a3b5298..6d985034f0 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S ++++ b/sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S +@@ -22,24 +22,14 @@ + .text + .globl __syscall_error + ENTRY(__libc_vfork) +- ld [%g7 + PID], %o5 +- cmp %o5, 0 +- bne 1f +- sub %g0, %o5, %o4 +- sethi %hi(0x80000000), %o4 +-1: st %o4, [%g7 + PID] +- + LOADSYSCALL(vfork) + ta 0x10 + bcc 2f + mov %o7, %g1 +- st %o5, [%g7 + PID] + call __syscall_error + mov %g1, %o7 + 2: sub %o1, 1, %o1 + andcc %o0, %o1, %o0 +- bne,a 1f +- st %o5, [%g7 + PID] + 1: retl + nop + END(__libc_vfork) +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/clone.S b/sysdeps/unix/sysv/linux/sparc/sparc64/clone.S +index b0f62660a7..6ffead88e2 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sparc64/clone.S ++++ b/sysdeps/unix/sysv/linux/sparc/sparc64/clone.S +@@ -76,13 +76,6 @@ END(__clone) + + .type __thread_start,@function + __thread_start: +- andcc %g4, CLONE_VM, %g0 +- bne,pt %icc, 1f +- set __NR_getpid,%g1 +- ta 0x6d +- st %o0,[%g7 + PID] +- st %o0,[%g7 + TID] +-1: + mov %g0, %fp /* terminate backtrace */ + call %g2 + mov %g3,%o0 +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S b/sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S +index 0818eba02e..298dd197a9 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S ++++ b/sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S +@@ -22,24 +22,14 @@ + .text + .globl __syscall_error + ENTRY(__libc_vfork) +- ld [%g7 + PID], %o5 +- sethi %hi(0x80000000), %o3 +- cmp %o5, 0 +- sub %g0, %o5, %o4 +- move %icc, %o3, %o4 +- st %o4, [%g7 + PID] +- + LOADSYSCALL(vfork) + ta 0x6d + bcc,pt %xcc, 2f + mov %o7, %g1 +- st %o5, [%g7 + PID] + call __syscall_error + mov %g1, %o7 + 2: sub %o1, 1, %o1 + andcc %o0, %o1, %o0 +- bne,a,pt %icc, 1f +- st %o5, [%g7 + PID] + 1: retl + nop + END(__libc_vfork) +diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c +index bb3eecfde1..b5f20a710b 100644 +--- a/sysdeps/unix/sysv/linux/spawni.c ++++ b/sysdeps/unix/sysv/linux/spawni.c +@@ -58,22 +58,19 @@ + normal program exit with the exit code 127. */ + #define SPAWN_ERROR 127 + +-/* We need to block both SIGCANCEL and SIGSETXID. */ +-#define SIGALL_SET \ +- ((__sigset_t) { .__val = {[0 ... _SIGSET_NWORDS-1 ] = -1 } }) +- + #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 + + +@@ -329,6 +326,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); +@@ -340,7 +342,9 @@ __spawnix (pid_t * pid, const char *file, + } + + /* Disable asynchronous cancellation. */ +- int cs = LIBC_CANCEL_ASYNC (); ++ int state; ++ __libc_ptf_call (__pthread_setcancelstate, ++ (PTHREAD_CANCEL_DISABLE, &state), 0); + + args.file = file; + args.exec = exec; +@@ -351,7 +355,7 @@ __spawnix (pid_t * pid, const char *file, + args.envp = envp; + args.xflags = xflags; + +- __sigprocmask (SIG_BLOCK, &SIGALL_SET, &args.oldmask); ++ __libc_signal_block_all (&args.oldmask); + + /* The clone flags used will create a new child that will run in the same + memory space (CLONE_VM) and the execution of calling thread will be +@@ -384,9 +388,9 @@ __spawnix (pid_t * pid, const char *file, + if ((ec == 0) && (pid != NULL)) + *pid = new_pid; + +- __sigprocmask (SIG_SETMASK, &args.oldmask, 0); ++ __libc_signal_restore_set (&args.oldmask); + +- LIBC_CANCEL_RESET (cs); ++ __libc_ptf_call (__pthread_setcancelstate, (state, NULL), 0); + + return ec; + } +diff --git a/sysdeps/unix/sysv/linux/syscalls.list b/sysdeps/unix/sysv/linux/syscalls.list +index 7ae2541f8f..248641b830 100644 +--- a/sysdeps/unix/sysv/linux/syscalls.list ++++ b/sysdeps/unix/sysv/linux/syscalls.list +@@ -18,6 +18,7 @@ execve - execve i:spp __execve execve + fdatasync - fdatasync Ci:i fdatasync + flock - flock i:ii __flock flock + get_kernel_syms EXTRA get_kernel_syms i:p __compat_get_kernel_syms get_kernel_syms@GLIBC_2.0:GLIBC_2.23 ++getpid - getpid Ei: __getpid getpid + getegid - getegid Ei: __getegid getegid + geteuid - geteuid Ei: __geteuid geteuid + getpgid - getpgid i:i __getpgid getpgid +diff --git a/sysdeps/unix/sysv/linux/sysdep.h b/sysdeps/unix/sysv/linux/sysdep.h +index a469f57121..e3ecd5638e 100644 +--- a/sysdeps/unix/sysv/linux/sysdep.h ++++ b/sysdeps/unix/sysv/linux/sysdep.h +@@ -48,6 +48,16 @@ + __LONG_LONG_PAIR ((long) ((val) >> 32), (long) ((val) & 0xffffffff)) + #endif + ++/* Provide a common macro to pass 64-bit value on pread and pwrite ++ syscalls. */ ++#ifdef __ASSUME_PRW_DUMMY_ARG ++# define SYSCALL_LL_PRW(val) 0, SYSCALL_LL (val) ++# define SYSCALL_LL64_PRW(val) 0, SYSCALL_LL64 (val) ++#else ++# define SYSCALL_LL_PRW(val) __ALIGNMENT_ARG SYSCALL_LL (val) ++# define SYSCALL_LL64_PRW(val) __ALIGNMENT_ARG SYSCALL_LL64 (val) ++#endif ++ + /* Provide a macro to pass the off{64}_t argument on p{readv,writev}{64}. */ + #define LO_HI_LONG(val) \ + (long) (val), \ +diff --git a/sysdeps/unix/sysv/linux/tile/Makefile b/sysdeps/unix/sysv/linux/tile/Makefile +index 1c1cfff280..43acea3633 100644 +--- a/sysdeps/unix/sysv/linux/tile/Makefile ++++ b/sysdeps/unix/sysv/linux/tile/Makefile +@@ -25,4 +25,5 @@ endif + ifeq ($(subdir),nptl) + # pull in __syscall_error routine + libpthread-routines += sysdep ++libpthread-shared-only-routines += sysdep + endif +diff --git a/sysdeps/unix/sysv/linux/tile/clone.S b/sysdeps/unix/sysv/linux/tile/clone.S +index d1d36462e7..3f9e3d56c4 100644 +--- a/sysdeps/unix/sysv/linux/tile/clone.S ++++ b/sysdeps/unix/sysv/linux/tile/clone.S +@@ -163,22 +163,6 @@ ENTRY (__clone) + .Lthread_start: + cfi_def_cfa_offset (FRAME_SIZE) + cfi_undefined (lr) +- /* Check and see if we need to reset the PID, which we do if +- CLONE_VM isn't set, i.e. it's a fork-like clone with a new +- address space. In that case we update the cached values +- from the true system pid (retrieved via __NR_getpid syscall). */ +- moveli r0, CLONE_VM +- and r0, r30, r0 +- BNEZ r0, .Lno_reset_pid /* CLONE_VM is set */ +- moveli TREG_SYSCALL_NR_NAME, __NR_getpid +- swint1 +- ADDLI_PTR r2, tp, PID_OFFSET +- { +- ST4 r2, r0 +- ADDLI_PTR r2, tp, TID_OFFSET +- } +- ST4 r2, r0 +-.Lno_reset_pid: + { + /* Invoke user function with specified argument. */ + move r0, r31 +diff --git a/sysdeps/unix/sysv/linux/tile/vfork.S b/sysdeps/unix/sysv/linux/tile/vfork.S +index d8c5ce3e24..2272777187 100644 +--- a/sysdeps/unix/sysv/linux/tile/vfork.S ++++ b/sysdeps/unix/sysv/linux/tile/vfork.S +@@ -29,18 +29,6 @@ + + .text + ENTRY (__vfork) +- { +- addli r11, tp, PID_OFFSET /* Point at PID. */ +- movei r13, 1 +- } +- { +- LD4U r12, r11 /* Load the saved PID. */ +- shli r13, r13, 31 /* Build 0x80000000. */ +- } +- sub r12, zero, r12 /* Negate it. */ +- CMOVEQZ r12, r12, r13 /* Replace zero pids. */ +- ST4 r11, r12 /* Store the temporary PID. */ +- + { + moveli r0, CLONE_VFORK | CLONE_VM | SIGCHLD + move r1, zero +@@ -52,22 +40,6 @@ ENTRY (__vfork) + moveli TREG_SYSCALL_NR_NAME, __NR_clone + swint1 + +- BEQZ r0, 1f /* If we are the parent... */ +- { +- addli r11, tp, PID_OFFSET /* Point at PID. */ +- movei r13, 1 +- } +- { +- LD4U r12, r11 /* Load the saved PID. */ +- shli r13, r13, 31 /* Build 0x80000000. */ +- } +- { +- CMPEQ r13, r12, r12 /* Test for that value. */ +- sub r12, zero, r12 /* Re-negate it. */ +- } +- CMOVNEZ r12, r13, zero /* Replace zero pids. */ +- ST4 r11, r12 /* Restore the PID. */ +-1: + BNEZ r1, 0f + jrp lr + PSEUDO_END (__vfork) +diff --git a/sysdeps/unix/sysv/linux/tst-clone2.c b/sysdeps/unix/sysv/linux/tst-clone2.c +index 68a7e6d6e2..1472311947 100644 +--- a/sysdeps/unix/sysv/linux/tst-clone2.c ++++ b/sysdeps/unix/sysv/linux/tst-clone2.c +@@ -28,8 +28,11 @@ + #include + #include + #include ++#include + +-#include /* for THREAD_* macros. */ ++#include /* For _STACK_GROWS_{UP,DOWN}. */ ++ ++#include + + static int sig; + static int pipefd[2]; +@@ -39,39 +42,35 @@ f (void *a) + { + close (pipefd[0]); + +- pid_t pid = THREAD_GETMEM (THREAD_SELF, pid); +- pid_t tid = THREAD_GETMEM (THREAD_SELF, tid); ++ pid_t ppid = getppid (); ++ pid_t pid = getpid (); ++ pid_t tid = syscall (__NR_gettid); + +- while (write (pipefd[1], &pid, sizeof pid) < 0) +- continue; +- while (write (pipefd[1], &tid, sizeof tid) < 0) +- continue; ++ if (write (pipefd[1], &ppid, sizeof ppid) != sizeof (ppid)) ++ FAIL_EXIT1 ("write ppid failed\n"); ++ if (write (pipefd[1], &pid, sizeof pid) != sizeof (pid)) ++ FAIL_EXIT1 ("write pid failed\n"); ++ if (write (pipefd[1], &tid, sizeof tid) != sizeof (tid)) ++ FAIL_EXIT1 ("write tid failed\n"); + + return 0; + } + + + static int +-clone_test (int clone_flags) ++do_test (void) + { + sig = SIGRTMIN; + sigset_t ss; + sigemptyset (&ss); + sigaddset (&ss, sig); + if (sigprocmask (SIG_BLOCK, &ss, NULL) != 0) +- { +- printf ("sigprocmask failed: %m\n"); +- return 1; +- } ++ FAIL_EXIT1 ("sigprocmask failed: %m"); + + if (pipe2 (pipefd, O_CLOEXEC)) +- { +- printf ("sigprocmask failed: %m\n"); +- return 1; +- } +- +- pid_t ppid = getpid (); ++ FAIL_EXIT1 ("pipe failed: %m"); + ++ int clone_flags = 0; + #ifdef __ia64__ + extern int __clone2 (int (*__fn) (void *__arg), void *__child_stack_base, + size_t __child_stack_size, int __flags, +@@ -88,61 +87,47 @@ clone_test (int clone_flags) + #error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP" + #endif + #endif ++ + close (pipefd[1]); + + if (p == -1) ++ FAIL_EXIT1("clone failed: %m"); ++ ++ pid_t ppid, pid, tid; ++ if (read (pipefd[0], &ppid, sizeof pid) != sizeof pid) + { +- printf ("clone failed: %m\n"); +- return 1; ++ kill (p, SIGKILL); ++ FAIL_EXIT1 ("read ppid failed: %m"); + } +- +- pid_t pid, tid; + if (read (pipefd[0], &pid, sizeof pid) != sizeof pid) + { +- printf ("read pid failed: %m\n"); + kill (p, SIGKILL); +- return 1; ++ FAIL_EXIT1 ("read pid failed: %m"); + } + if (read (pipefd[0], &tid, sizeof tid) != sizeof tid) + { +- printf ("read pid failed: %m\n"); + kill (p, SIGKILL); +- return 1; ++ FAIL_EXIT1 ("read tid failed: %m"); + } + + close (pipefd[0]); + + int ret = 0; + +- /* For CLONE_VM glibc clone implementation does not change the pthread +- pid/tid field. */ +- if ((clone_flags & CLONE_VM) == CLONE_VM) +- { +- if ((ppid != pid) || (ppid != tid)) +- { +- printf ("parent pid (%i) != received pid/tid (%i/%i)\n", +- (int)ppid, (int)pid, (int)tid); +- ret = 1; +- } +- } +- /* For any other flag clone updates the new pthread pid and tid with +- the clone return value. */ +- else +- { +- if ((p != pid) || (p != tid)) +- { +- printf ("child pid (%i) != received pid/tid (%i/%i)\n", +- (int)p, (int)pid, (int)tid); +- ret = 1; +- } +- } ++ pid_t own_pid = getpid (); ++ pid_t own_tid = syscall (__NR_gettid); ++ ++ /* Some sanity checks for clone syscall: returned ppid should be current ++ pid and both returned tid/pid should be different from current one. */ ++ if ((ppid != own_pid) || (pid == own_pid) || (tid == own_tid)) ++ FAIL_RET ("ppid=%i pid=%i tid=%i | own_pid=%i own_tid=%i", ++ (int)ppid, (int)pid, (int)tid, (int)own_pid, (int)own_tid); + + int e; + if (waitpid (p, &e, __WCLONE) != p) + { +- puts ("waitpid failed"); + kill (p, SIGKILL); +- return 1; ++ FAIL_EXIT1 ("waitpid failed"); + } + if (!WIFEXITED (e)) + { +@@ -150,29 +135,12 @@ clone_test (int clone_flags) + printf ("died from signal %s\n", strsignal (WTERMSIG (e))); + else + puts ("did not terminate correctly"); +- return 1; ++ exit (EXIT_FAILURE); + } + if (WEXITSTATUS (e) != 0) +- { +- printf ("exit code %d\n", WEXITSTATUS (e)); +- return 1; +- } ++ FAIL_EXIT1 ("exit code %d", WEXITSTATUS (e)); + + return ret; + } + +-int +-do_test (void) +-{ +- /* First, check that the clone implementation, without any flag, updates +- the struct pthread to contain the new PID and TID. */ +- int ret = clone_test (0); +- /* Second, check that with CLONE_VM the struct pthread PID and TID fields +- remain unmodified after the clone. Any modifications would cause problem +- for the parent as described in bug 19957. */ +- ret += clone_test (CLONE_VM); +- return ret; +-} +- +-#define TEST_FUNCTION do_test () +-#include "../test-skeleton.c" ++#include +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/clone.S b/sysdeps/unix/sysv/linux/x86_64/clone.S +index 66f4b11490..5629aed395 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/clone.S ++++ b/sysdeps/unix/sysv/linux/x86_64/clone.S +@@ -91,14 +91,6 @@ L(thread_start): + the outermost frame obviously. */ + xorl %ebp, %ebp + +- andq $CLONE_VM, %rdi +- jne 1f +- movl $SYS_ify(getpid), %eax +- syscall +- movl %eax, %fs:PID +- movl %eax, %fs:TID +-1: +- + /* Set up arguments for the function call. */ + popq %rax /* Function to call. */ + popq %rdi /* Argument. */ +diff --git a/sysdeps/unix/sysv/linux/x86_64/vfork.S b/sysdeps/unix/sysv/linux/x86_64/vfork.S +index 8332ade9fb..cdd2dea32a 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/vfork.S ++++ b/sysdeps/unix/sysv/linux/x86_64/vfork.S +@@ -34,16 +34,6 @@ ENTRY (__vfork) + cfi_adjust_cfa_offset(-8) + cfi_register(%rip, %rdi) + +- /* Save the TCB-cached PID away in %esi, and then negate the TCB +- field. But if it's zero, set it to 0x80000000 instead. See +- raise.c for the logic that relies on this value. */ +- movl %fs:PID, %esi +- movl $0x80000000, %ecx +- movl %esi, %edx +- negl %edx +- cmove %ecx, %edx +- movl %edx, %fs:PID +- + /* Stuff the syscall number in RAX and enter into the kernel. */ + movl $SYS_ify (vfork), %eax + syscall +@@ -52,14 +42,6 @@ ENTRY (__vfork) + pushq %rdi + cfi_adjust_cfa_offset(8) + +- /* Restore the original value of the TCB cache of the PID, if we're +- the parent. But in the child (syscall return value equals zero), +- leave things as they are. */ +- testq %rax, %rax +- je 1f +- movl %esi, %fs:PID +-1: +- + cmpl $-4095, %eax + jae SYSCALL_ERROR_LABEL /* Branch forward if it failed. */ + +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 9ce4b495a5..9eca98817d 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, +@@ -88,6 +89,71 @@ get_common_indeces (struct cpu_features *cpu_features, + cpu_features->feature[index_arch_FMA_Usable] + |= bit_arch_FMA_Usable; + } ++ ++ /* 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; ++ } ++ } ++ } ++ } + } + } + +@@ -133,8 +199,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: +@@ -205,6 +269,16 @@ init_cpu_features (struct cpu_features *cpu_features) + if (CPU_FEATURES_ARCH_P (cpu_features, AVX2_Usable)) + cpu_features->feature[index_arch_AVX_Fast_Unaligned_Load] + |= bit_arch_AVX_Fast_Unaligned_Load; ++ ++ /* 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 97ffe765f4..507a141414 100644 +--- a/sysdeps/x86/cpu-features.h ++++ b/sysdeps/x86/cpu-features.h +@@ -37,6 +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_Prefer_No_AVX512 (1 << 20) ++#define bit_arch_XSAVEC_Usable (1 << 21) + + /* CPUID Feature flags. */ + +@@ -60,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) +@@ -74,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 +@@ -107,6 +123,9 @@ + # define index_arch_Prefer_No_VZEROUPPER FEATURE_INDEX_1*FEATURE_SIZE + # define index_arch_Fast_Unaligned_Copy FEATURE_INDEX_1*FEATURE_SIZE + # 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) +@@ -195,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]; + }; + +@@ -232,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 +@@ -250,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 +@@ -277,6 +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_Prefer_No_AVX512 FEATURE_INDEX_1 ++# define index_arch_XSAVEC_Usable FEATURE_INDEX_1 + + #endif /* !__ASSEMBLER__ */ + +diff --git a/sysdeps/x86_64/Makefile b/sysdeps/x86_64/Makefile +index 6d99284cd0..cc990a9685 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 +@@ -49,9 +49,12 @@ extra-test-objs += tst-quadmod1pie.o tst-quadmod2pie.o + $(objpfx)tst-quad1pie: $(objpfx)tst-quadmod1pie.o + $(objpfx)tst-quad2pie: $(objpfx)tst-quadmod2pie.o + +-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 +@@ -62,7 +65,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 +@@ -89,6 +93,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) +@@ -96,14 +104,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 ed0c1a8efd..8355432dfc 100644 +--- a/sysdeps/x86_64/dl-machine.h ++++ b/sysdeps/x86_64/dl-machine.h +@@ -66,9 +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_avx512 (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; +@@ -117,12 +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)) +- *(ElfW(Addr) *) (got + 2) = (ElfW(Addr)) &_dl_runtime_resolve_avx512; +- else if (HAS_ARCH_FEATURE (AVX_Usable)) +- *(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 cf6c107f54..fa5bf6cd93 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 12f1a5cf84..b4cda0f535 100644 +--- a/sysdeps/x86_64/dl-trampoline.S ++++ b/sysdeps/x86_64/dl-trampoline.S +@@ -18,6 +18,7 @@ + + #include + #include ++#include + #include + + #ifndef DL_STACK_ALIGNMENT +@@ -33,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) +@@ -79,50 +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_profile _dl_runtime_profile_avx512 + #include "dl-trampoline.h" +-#undef _dl_runtime_resolve + #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_profile _dl_runtime_profile_avx + #include "dl-trampoline.h" +-#undef _dl_runtime_resolve + #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_profile ++#undef VEC ++#undef VMOVA ++#undef VEC_SIZE ++ ++#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 b90836ab13..b9c2f1796f 100644 +--- a/sysdeps/x86_64/dl-trampoline.h ++++ b/sysdeps/x86_64/dl-trampoline.h +@@ -16,40 +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 ++# 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 +-#else +-# define REGISTER_SAVE_AREA REGISTER_SAVE_AREA_RAW ++ ++# if (STATE_SAVE_OFFSET % STATE_SAVE_ALIGNMENT) != 0 ++# error STATE_SAVE_OFFSET must be multples of STATE_SAVE_ALIGNMENT ++# endif ++ ++# 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 ++# 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 ++# 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 +-#endif + +- .text + .globl _dl_runtime_resolve + .hidden _dl_runtime_resolve + .type _dl_runtime_resolve, @function +@@ -57,19 +64,30 @@ + 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 + cfi_adjust_cfa_offset(REGISTER_SAVE_AREA) ++# 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) +@@ -78,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 +@@ -138,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)) +@@ -160,9 +153,10 @@ _dl_runtime_resolve: + jmp *%r11 # Jump to function address. + cfi_endproc + .size _dl_runtime_resolve, .-_dl_runtime_resolve ++#endif + + +-#ifndef PROF ++#if !defined PROF && defined _dl_runtime_profile + # if (LR_VECTOR_OFFSET % VEC_SIZE) != 0 + # error LR_VECTOR_OFFSET must be multples of VEC_SIZE + # endif +diff --git a/sysdeps/x86_64/memcpy_chk.S b/sysdeps/x86_64/memcpy_chk.S +index 2296b55119..a95b3ad3cf 100644 +--- a/sysdeps/x86_64/memcpy_chk.S ++++ b/sysdeps/x86_64/memcpy_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 + memcpy bringing in __chk_fail and all routines +diff --git a/sysdeps/x86_64/multiarch/memcpy.S b/sysdeps/x86_64/multiarch/memcpy.S +index b8677596f9..ea4ec70d1a 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 9d92c8a7e3..26b49de6f6 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 ff5e041420..ef92afde5a 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 7f861206df..a9129c460a 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 51970687cf..87c8299fea 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 9e49f6f26e..642c67973b 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-vec-unaligned-erms.S b/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S +index 28e71fd576..acf448c9a6 100644 +--- a/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S +@@ -110,6 +110,8 @@ ENTRY (__memset_erms) + ENTRY (MEMSET_SYMBOL (__memset, erms)) + # endif + L(stosb): ++ /* Issue vzeroupper before rep stosb. */ ++ VZEROUPPER + movq %rdx, %rcx + movzbl %sil, %eax + movq %rdi, %rdx +diff --git a/sysdeps/x86_64/multiarch/memset.S b/sysdeps/x86_64/multiarch/memset.S +index 96e99341aa..eae39e2ecd 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 2efe6ed909..38d7bef6df 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/nptl/tcb-offsets.sym b/sysdeps/x86_64/nptl/tcb-offsets.sym +index aeb752673a..8a25c482cb 100644 +--- a/sysdeps/x86_64/nptl/tcb-offsets.sym ++++ b/sysdeps/x86_64/nptl/tcb-offsets.sym +@@ -4,7 +4,6 @@ + + RESULT offsetof (struct pthread, result) + TID offsetof (struct pthread, tid) +-PID offsetof (struct pthread, pid) + CANCELHANDLING offsetof (struct pthread, cancelhandling) + CLEANUP_JMP_BUF offsetof (struct pthread, cleanup_jmp_buf) + CLEANUP offsetof (struct pthread, cleanup) +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/sysdep.h b/sysdeps/x86_64/sysdep.h +index 75ac747be8..4b67fa80c1 100644 +--- a/sysdeps/x86_64/sysdep.h ++++ b/sysdeps/x86_64/sysdep.h +@@ -89,13 +89,14 @@ lose: \ + END (name) + + #undef JUMPTARGET +-#ifdef PIC ++#ifdef SHARED + # ifdef BIND_NOW + # define JUMPTARGET(name) *name##@GOTPCREL(%rip) + # else + # define JUMPTARGET(name) name##@PLT + # endif + #else ++/* For static archives, branch to target directly. */ + # define JUMPTARGET(name) name + #endif + +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); ++}