git-updates
authorGNU Libc Maintainers <debian-glibc@lists.debian.org>
Sat, 2 Dec 2017 10:07:17 +0000 (10:07 +0000)
committerAurelien Jarno <aurel32@debian.org>
Sat, 2 Dec 2017 10:07:17 +0000 (10:07 +0000)
GIT update of git://sourceware.org/git/glibc.git/release/2.25/master from glibc-2.25

Gbp-Pq: Name git-updates.diff

205 files changed:
ChangeLog
INSTALL
Makeconfig
Makerules
NEWS
assert/Makefile
assert/assert.h
assert/tst-assert-c++.cc [new file with mode: 0644]
assert/tst-assert-g++.cc [new file with mode: 0644]
config.make.in
configure
configure.ac
elf/Makefile
elf/dl-tunable-types.h
elf/dl-tunables.c
elf/rtld.c
elf/tst-env-setuid.c
grp/grp-merge.c
iconvdata/Makefile
include/resolv.h
inet/Makefile
inet/deadline.c [new file with mode: 0644]
inet/net-internal.h
inet/tst-deadline.c [new file with mode: 0644]
io/fts.h
localedata/ChangeLog
localedata/locales/iso14651_t1_common
malloc/arena.c
malloc/malloc.c
misc/regexp.c
nptl/Makefile
nptl/allocatestack.c
nptl/pt-longjmp.c
nptl/pt-system.c
nptl/pthread_mutex_lock.c
nptl/pthread_mutex_timedlock.c
nptl/pthread_rwlock_common.c
nptl/tst-compat-forwarder-mod.c [new file with mode: 0644]
nptl/tst-compat-forwarder.c [new file with mode: 0644]
nptl/tst-mutex7.c
nptl/tst-mutex7robust.c [new file with mode: 0644]
nptl/tst-rwlock20.c [new file with mode: 0644]
posix/Makefile
posix/flexmember.h [new file with mode: 0644]
posix/glob.c
posix/glob64.c
posix/glob_internal.h [new file with mode: 0644]
posix/glob_pattern_p.c [new file with mode: 0644]
posix/globfree.c [new file with mode: 0644]
posix/globfree64.c [new file with mode: 0644]
posix/globtest.sh
posix/tst-glob-tilde.c [new file with mode: 0644]
resolv/Makefile
resolv/res_mkquery.c
resolv/res_query.c
resolv/resolv-internal.h
resolv/tst-resolv-edns.c [new file with mode: 0644]
resolv/tst-resolv-qtypes.c
scripts/backport-support.sh [new file with mode: 0644]
stdlib/getentropy.c
string/stratcliff.c
string/test-memchr.c
sunrpc/Makefile
sunrpc/clnt_udp.c
sunrpc/tst-udp-error.c [new file with mode: 0644]
sunrpc/tst-udp-garbage.c [new file with mode: 0644]
sunrpc/tst-udp-nonblocking.c [new file with mode: 0644]
sunrpc/tst-udp-timeout.c [new file with mode: 0644]
support/Makefile
support/capture_subprocess.h [new file with mode: 0644]
support/check.h
support/namespace.h
support/resolv_test.c
support/resolv_test.h
support/support-xstat.c [new file with mode: 0644]
support/support.h
support/support_can_chroot.c [new file with mode: 0644]
support/support_capture_subprocess.c [new file with mode: 0644]
support/support_capture_subprocess_check.c [new file with mode: 0644]
support/support_chroot.c [new file with mode: 0644]
support/support_enter_network_namespace.c
support/support_format_addrinfo.c
support/support_format_dns_packet.c
support/support_format_hostent.c
support/support_isolate_in_subprocess.c [new file with mode: 0644]
support/support_run_diff.c
support/support_shared_allocate.c [new file with mode: 0644]
support/support_test_main.c
support/support_test_verify_impl.c
support/support_write_file_string.c [new file with mode: 0644]
support/temp_file.c
support/test-driver.c
support/test-driver.h
support/tst-support-namespace.c
support/tst-support_capture_subprocess.c [new file with mode: 0644]
support/tst-support_format_dns_packet.c [new file with mode: 0644]
support/tst-support_record_failure-2.sh
support/tst-support_record_failure.c
support/xaccept4.c [new file with mode: 0644]
support/xchroot.c [new file with mode: 0644]
support/xclose.c [new file with mode: 0644]
support/xdlfcn.c [new file with mode: 0644]
support/xdlfcn.h [new file with mode: 0644]
support/xdup2.c [new file with mode: 0644]
support/xmkdir.c [new file with mode: 0644]
support/xmprotect.c [new file with mode: 0644]
support/xopen.c [new file with mode: 0644]
support/xpipe.c [new file with mode: 0644]
support/xpthread_attr_setguardsize.c [new file with mode: 0644]
support/xpthread_rwlock_init.c [new file with mode: 0644]
support/xpthread_rwlock_rdlock.c [new file with mode: 0644]
support/xpthread_rwlock_unlock.c [new file with mode: 0644]
support/xpthread_rwlock_wrlock.c [new file with mode: 0644]
support/xpthread_rwlockattr_init.c [new file with mode: 0644]
support/xpthread_rwlockattr_setkind_np.c [new file with mode: 0644]
support/xsocket.h
support/xthread.h
support/xunistd.h
sysdeps/aarch64/dl-machine.h
sysdeps/generic/unsecvars.h
sysdeps/gnu/glob64.c
sysdeps/gnu/globfree64.c [new file with mode: 0644]
sysdeps/hppa/__longjmp.c
sysdeps/hppa/dl-fptr.c
sysdeps/hppa/dl-machine.h
sysdeps/hppa/dl-trampoline.S
sysdeps/hppa/math-tests.h [new file with mode: 0644]
sysdeps/hppa/nptl/bits/pthreadtypes.h
sysdeps/i386/i686/fpu/multiarch/libm-test-ulps
sysdeps/i386/i686/multiarch/memchr-sse2.S
sysdeps/i386/i686/multiarch/strcspn-c.c
sysdeps/i386/i686/multiarch/varshift.c
sysdeps/mips/bits/long-double.h [deleted file]
sysdeps/mips/ieee754/bits/long-double.h [new file with mode: 0644]
sysdeps/nptl/fork.c
sysdeps/powerpc/power7/fpu/s_logbl.c
sysdeps/powerpc/powerpc32/dl-machine.h
sysdeps/sparc/sparc32/dl-machine.h
sysdeps/sparc/sparc64/dl-machine.h
sysdeps/unix/sysv/linux/Makefile
sysdeps/unix/sysv/linux/alpha/glob.c
sysdeps/unix/sysv/linux/alpha/globfree.c [new file with mode: 0644]
sysdeps/unix/sysv/linux/alpha/localplt.data
sysdeps/unix/sysv/linux/hppa/bits/shm.h
sysdeps/unix/sysv/linux/hppa/clone.S
sysdeps/unix/sysv/linux/hppa/getcontext.S
sysdeps/unix/sysv/linux/hppa/internaltypes.h [deleted file]
sysdeps/unix/sysv/linux/hppa/ipc_priv.h [new file with mode: 0644]
sysdeps/unix/sysv/linux/hppa/localplt.data
sysdeps/unix/sysv/linux/hppa/pt-vfork.S
sysdeps/unix/sysv/linux/hppa/pthread.h
sysdeps/unix/sysv/linux/hppa/pthread_cond_broadcast.c [deleted file]
sysdeps/unix/sysv/linux/hppa/pthread_cond_destroy.c [deleted file]
sysdeps/unix/sysv/linux/hppa/pthread_cond_init.c [deleted file]
sysdeps/unix/sysv/linux/hppa/pthread_cond_signal.c [deleted file]
sysdeps/unix/sysv/linux/hppa/pthread_cond_wait.c [deleted file]
sysdeps/unix/sysv/linux/hppa/setcontext.S
sysdeps/unix/sysv/linux/hppa/sysdep-cancel.h
sysdeps/unix/sysv/linux/hppa/sysdep.h
sysdeps/unix/sysv/linux/i386/glob64.c
sysdeps/unix/sysv/linux/i386/localplt.data
sysdeps/unix/sysv/linux/mips/mips64/n64/globfree64.c [new file with mode: 0644]
sysdeps/unix/sysv/linux/mips/mips64/n64/posix_fadvise64.c
sysdeps/unix/sysv/linux/oldglob.c [new file with mode: 0644]
sysdeps/unix/sysv/linux/s390/pt-longjmp.c
sysdeps/unix/sysv/linux/sparc/bits/long-double.h [deleted file]
sysdeps/unix/sysv/linux/sparc/sparc32/bits/long-double.h [new file with mode: 0644]
sysdeps/unix/sysv/linux/sparc/sparc64/bits/long-double.h [new file with mode: 0644]
sysdeps/unix/sysv/linux/spawni.c
sysdeps/unix/sysv/linux/wordsize-64/globfree64.c [new file with mode: 0644]
sysdeps/unix/sysv/linux/x86_64/x32/globfree.c [new file with mode: 0644]
sysdeps/wordsize-64/glob.c
sysdeps/wordsize-64/globfree.c [new file with mode: 0644]
sysdeps/wordsize-64/globfree64.c [new file with mode: 0644]
sysdeps/x86/cpu-features-offsets.sym
sysdeps/x86/cpu-features.c
sysdeps/x86/cpu-features.h
sysdeps/x86/fpu/test-math-vector-sincos.h
sysdeps/x86_64/Makefile
sysdeps/x86_64/dl-machine.h
sysdeps/x86_64/dl-tls.c [new file with mode: 0644]
sysdeps/x86_64/dl-tls.h
sysdeps/x86_64/dl-trampoline.S
sysdeps/x86_64/dl-trampoline.h
sysdeps/x86_64/localplt.data
sysdeps/x86_64/mempcpy_chk.S
sysdeps/x86_64/multiarch/memcpy.S
sysdeps/x86_64/multiarch/memcpy_chk.S
sysdeps/x86_64/multiarch/memmove.S
sysdeps/x86_64/multiarch/memmove_chk.S
sysdeps/x86_64/multiarch/mempcpy.S
sysdeps/x86_64/multiarch/mempcpy_chk.S
sysdeps/x86_64/multiarch/memset.S
sysdeps/x86_64/multiarch/memset_chk.S
sysdeps/x86_64/rtld-offsets.sym [new file with mode: 0644]
sysdeps/x86_64/tls_get_addr.S [new file with mode: 0644]
sysdeps/x86_64/tlsdesc.sym
sysdeps/x86_64/tst-avx-aux.c [new file with mode: 0644]
sysdeps/x86_64/tst-avx.c [new file with mode: 0644]
sysdeps/x86_64/tst-avx512-aux.c [new file with mode: 0644]
sysdeps/x86_64/tst-avx512.c [new file with mode: 0644]
sysdeps/x86_64/tst-avx512mod.c [new file with mode: 0644]
sysdeps/x86_64/tst-avxmod.c [new file with mode: 0644]
sysdeps/x86_64/tst-sse.c [new file with mode: 0644]
sysdeps/x86_64/tst-ssemod.c [new file with mode: 0644]

index f140ee67de3306480abb785fbfb75b986c0d311e..f85bf022b9acffd6b67e212deb83f43f9d3d4f6a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,709 @@
+2017-11-02  Florian Weimer  <fweimer@redhat.com>
+
+       [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 <eggert@cs.ucla.edu>
+
+       [BZ #22332]
+       * posix/glob.c (__glob): Fix buffer overflow during GLOB_TILDE
+       unescaping.
+
+2017-10-21  Florian Weimer  <fweimer@redhat.com>
+
+       * 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 <eggert@cs.ucla.edu>
+
+       [BZ #22320]
+       CVE-2017-15670
+       * posix/glob.c (__glob): Fix one-byte overflow.
+
+2017-09-08  Adhemerval Zanella  <adhemerval.zanella@linaro.org>
+
+       [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  <hongjiu.lu@intel.com>
+
+       [BZ #18822]
+       * sysdeps/unix/sysv/linux/i386/glob64.c (__old_glob64): Add
+       libc_hidden_proto and libc_hidden_def.
+
+2017-03-14  Adhemerval Zanella  <adhemerval.zanella@linaro.org>
+
+       [BZ #21232]
+       * sysdeps/unix/sysv/linux/mips/mips64/n64/posix_fadvise64.c: Add
+       posix_fadvise64 weak_alias for static build.
+
+2017-10-23  Adhemerval Zanella  <adhemerval.zanella@linaro.org>
+
+       * sysdeps/unix/sysv/linux/spawni.c (__spawnix): Use 0 instead of
+       WNOHANG in waitpid call.
+
+2017-10-20  Adhemerval Zanella  <adhemerval.zanella@linaro.org>
+
+       [BZ #22273]
+       * sysdeps/unix/sysv/linux/spawni.c (__spawnix): Handle the case where
+       the auxiliary process is terminated by a signal before calling _exit
+       or execve.
+
+2017-08-09  Andreas Schwab  <schwab@suse.de>
+
+       * nptl/Makefile (tests) [$(build-shared) = yes]: Add
+       tst-compat-forwarder.
+       (modules-names): Add tst-compat-forwarder-mod.
+       ($(objpfx)tst-compat-forwarder): Depend on
+       $(objpfx)tst-compat-forwarder-mod.so.
+       * nptl/tst-compat-forwarder.c: New file.
+       * nptl/tst-compat-forwarder-mod.c: New file.
+
+2017-08-09  Andreas Schwab  <schwab@suse.de>
+
+       * sysdeps/unix/sysv/linux/s390/pt-longjmp.c: Update reference to
+       renamed alias.
+
+2017-08-08  Andreas Schwab  <schwab@suse.de>
+
+       [BZ #21041]
+       * nptl/pt-longjmp.c (longjmp, siglongjmp): Don't use IFUNC resolver.
+       * nptl/pt-system.c (system): Likewise.
+
+2017-10-13  James Clarke  <jrtc27@jrtc27.com>
+
+       * sysdeps/powerpc/powerpc32/dl-machine.h (elf_machine_rela):
+       Assign sym_map to be map for local symbols, as TLS relocations
+       use sym_map to determine whether the symbol is defined and to
+       extract the TLS information.
+       * sysdeps/sparc/sparc32/dl-machine.h (elf_machine_rela): Likewise.
+       * sysdeps/sparc/sparc64/dl-machine.h (elf_machine_rela): Likewise.
+
+2017-10-19  Joseph Myers  <joseph@codesourcery.com>
+
+       [BZ #22322]
+       * sysdeps/mips/bits/long-double.h: Move to ....
+       * sysdeps/mips/ieee754/bits/long-double.h: ... here.
+
+2017-10-22  H.J. Lu  <hongjiu.lu@intel.com>
+
+       [BZ #21265]
+       * sysdeps/x86/cpu-features-offsets.sym (XSAVE_STATE_SIZE_OFFSET):
+       New.
+       * sysdeps/x86/cpu-features.c: Include <libc-internal.h>.
+       (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-offsets.h>.
+       (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  <hongjiu.lu@intel.com>
+
+       * sysdeps/x86_64/Makefile (tests): Add tst-sse, tst-avx and
+       tst-avx512.
+       (test-extras): Add tst-avx-aux and tst-avx512-aux.
+       (extra-test-objs): Add tst-avx-aux.o and tst-avx512-aux.o.
+       (modules-names): Add tst-ssemod, tst-avxmod and tst-avx512mod.
+       ($(objpfx)tst-sse): New rule.
+       ($(objpfx)tst-avx): Likewise.
+       ($(objpfx)tst-avx512): Likewise.
+       (CFLAGS-tst-avx-aux.c): New.
+       (CFLAGS-tst-avxmod.c): Likewise.
+       (CFLAGS-tst-avx512-aux.c): Likewise.
+       (CFLAGS-tst-avx512mod.c): Likewise.
+       * sysdeps/x86_64/tst-avx-aux.c: New file.
+       * sysdeps/x86_64/tst-avx.c: Likewise.
+       * sysdeps/x86_64/tst-avx512-aux.c: Likewise.
+       * sysdeps/x86_64/tst-avx512.c: Likewise.
+       * sysdeps/x86_64/tst-avx512mod.c: Likewise.
+       * sysdeps/x86_64/tst-avxmod.c: Likewise.
+       * sysdeps/x86_64/tst-sse.c: Likewise.
+       * sysdeps/x86_64/tst-ssemod.c: Likewise.
+
+2017-07-19  DJ Delorie  <dj@delorie.com>
+
+       [BZ #21654]
+       * grp/grp-merge.c (libc_hidden_def): Fix cast-after-dereference.
+
+2017-07-14  DJ Delorie  <dj@redhat.com>
+
+       [BZ #21654]
+       * grp/grp_merge.c (__copy_grp): Align char** to minimum pointer
+       alignment not char alignment.
+       (__merge_grp): Likewise.
+
+2017-08-22  Joseph Myers  <joseph@codesourcery.com>
+
+       [BZ #21987]
+       * sysdeps/unix/sysv/linux/sparc/bits/long-double.h: Remove file
+       and copy to ...
+       * sysdeps/unix/sysv/linux/sparc/sparc32/bits/long-double.h:
+       ... here.
+       * sysdeps/unix/sysv/linux/sparc/sparc64/bits/long-double.h:
+       ... and here.
+
+2017-09-11  H.J. Lu  <hongjiu.lu@intel.com>
+           Florian Weimer <fweimer@redhat.com>
+
+       * configure.ac (find_cxx_header): Suppress compiler error message.
+       * configure: Regenerated.
+
+       [BZ #21573]
+       * Makerules [$(c++-bits-std_abs-h) != ""] (before-compile): Add
+       $(common-objpfx)bits/std_abs.h.
+       [$(c++-bits-std_abs-h) != ""] ($(common-objpfx)bits/std_abs.h):
+       New target.
+       * config.make.in (c++-bits-std_abs-h): New.
+       * configure.ac (find_cxx_header): Use "\,$1," with sed.
+       (CXX_BITS_STD_ABS_H): New.
+       (AC_SUBST(CXX_BITS_STD_ABS_H)): Likewise.
+       * configure: Regenerated.
+
+2017-09-11  H.J. Lu  <hongjiu.lu@intel.com>
+
+       [BZ #21982]
+       * string/stratcliff.c (do_test): Declare size, nchars, inner,
+       middle and outer with size_t instead of int.  Repleace %d and
+       %Zd with %zu in printf.  Update "MAX (0, nchars - 128)" and
+       "MAX (outer, nchars - 64)" to support unsigned outer and
+       nchars.  Also exit loop when outer == 0.
+
+2017-09-07  H.J. Lu  <hongjiu.lu@intel.com>
+
+       * resolv/tst-resolv-qtypes.c (domain): Changed to
+       "const char domain[] =".
+
+2017-08-31  H.J. Lu  <hongjiu.lu@intel.com>
+
+       [BZ #22051]
+       * Makerules (build-module-helper-objlist): Filter out
+       $(elf-objpfx)sofini.os.
+       (build-shlib-objlist): Append $(elf-objpfx)sofini.os if it is
+       needed.
+
+2017-07-29  Torvald Riegel  <triegel@redhat.com>
+           Carlos O'Donell  <carlos@redhat.com>
+
+       [BZ 21778]
+       * nptl/pthread_mutex_timedlock.c (__pthread_mutex_timedlock): Update
+       oldval if the CAS fails.
+       * nptl/pthread_mutex_lock.c (__pthread_mutex_lock_full): Likewise.
+       * nptl/tst-mutex7.c: Add comments explaining template test.
+       (ROBUST, DELAY_NSEC, ROUNDS, N): New.
+       (tf, do_test): Use them.
+       * nptl/tst-mutex7robust.c: New file.
+       * nptl/Makefile (tests): Add new test.
+
+2017-07-28  Torvald Riegel  <triegel@redhat.com>
+           Carlos O'Donell  <carlos@redhat.com>
+
+       [BZ #21298]
+       * nptl/Makefile (tests): Add tst-rwlock20.
+       * nptl/pthread_rwlock_common.c (__pthread_rwlock_rdlock_full): Fix
+       explicit hand-over.
+       (__pthread_rwlock_wrlock_full): Likewise.
+       * nptl/tst-rwlock20.c: New file.
+
+2017-08-21  Florian Weimer  <fweimer@redhat.com>
+
+       [BZ #21972]
+       * assert/assert.h (assert): Use static_cast (bool) for C++.
+       Use the ternary operator in the warning branch for GNU C.
+       * assert/Makefile (tests): Add tst-assert-c++, tst-assert-g++.
+       (CFLAGS-tst-assert-c++.o): Compile in C++11 mode.
+       (CFLAGS-tst-assert-g++.o): Compile in GnU C++11 mode.
+       (LDLIBS-tst-assert-c++, LDLIBS-tst-assert-g++): Link with libstdc++.
+       * assert/tst-assert-c++.cc, assert/tst-assert-g++.cc: New files.
+
+2017-04-13  Florian Weimer  <fweimer@redhat.com>
+
+       [BZ #21361]
+       Limit EDNS buffer size to 1200 bytes.
+       * include/resolv.h (__res_nopt): Remove declaration.
+       * resolv/Makefile (tests): tst-resolv-edns.
+       (tst-resolv-edns): Link with -lresolv, -lpthread.
+       * resolv/res_mkquery.c (__res_ntop): Limit EDNS buffer size to the
+       interval [512, 1200].
+       * resolv/res_query.c (__libc_res_nquery): Use 1200 buffer size if
+       we can resize the buffer.
+       * resolv/resolv-internal.h (RESOLV_EDNS_BUFFER_SIZE): Define.
+       (__res_nopt): Declare.
+       * resolv/tst-resolv-edns.c: New file.
+       * resolv/resolv_test.h (struct resolv_edns_info): Define.
+       (struct resolv_response_context): Add edns member.
+       * resolv/resolv_test.c (struct query_info): Add edns member.
+       (parse_query): Extract EDNS information from the query.
+       (server_thread_udp_process_one): Propagate EDNS data.
+       (server_thread_tcp_client): Likewise.
+
+2017-08-12  John David Anglin  <danglin@gcc.gnu.org>
+
+       [BZ 19170]
+       * sysdeps/hppa/dl-trampoline.S (_dl_runtime_resolve): Return to caller
+       if _dl_fixup fails.
+
+2017-08-12  John David Anglin  <danglin@gcc.gnu.org>
+           Adhemerval Zanella  <adhemerval.zanella@linaro.org>
+
+       [BZ #21512]
+       * sysdeps/unix/sysv/linux/aarch64/clone.S (__clone): Call exit
+       syscall instead of jump to _exit.
+       * sysdeps/unix/sysv/linux/hppa/localplt.data: Remove _exit entry.
+
+2017-08-12  Adhemerval Zanella  <adhemerval.zanella@linaro.org>
+
+       * sysdeps/unix/sysv/linux/hppa/ipc_priv.h: New file.
+
+2017-08-12  John David Anglin  <danglin@gcc.gnu.org>
+
+       * sysdeps/unix/sysv/linux/hppa/clone.S (__clone): Add .cfi annotation.
+       * sysdeps/unix/sysv/linux/hppa/getcontext.S (__getcontext): Likewise.
+       * sysdeps/unix/sysv/linux/hppa/pt-vfork.S (__vfork): Likewise.
+       * sysdeps/unix/sysv/linux/hppa/setcontext.S (__setcontext): Likewise.
+
+       * sysdeps/unix/sysv/linux/hppa/getcontext.S (__getcontext): Fix stack
+       offset for r19 load.
+
+       * sysdeps/unix/sysv/linux/hppa/setcontext.S (__setcontext): Return 0.
+
+       * sysdeps/unix/sysv/linux/hppa/sysdep-cancel.h (PSEUDO): Fix CFA offset.
+       Use .cfi_def_cfa_offset instead of .cfi_offset.  Don't record stack
+       pointer offset.  Correct PIC register offset.  Don't mention frame
+       related instructions in epilogue.
+       (PUSHARGS_1): Correct offset.
+       (PUSHARGS_2): Likewise.
+       (PUSHARGS_3): Likewise.
+       (PUSHARGS_4): Likewise.
+       (PUSHARGS_5): Likewise.
+       (PUSHARGS_6): Likewise.
+       (POPARGS_1): Don't mention register restore.
+       (POPARGS_2): Likewise.
+       (POPARGS_3): Likewise.
+       (POPARGS_4): Likewise.
+       (POPARGS_5): Likewise.
+       (POPARGS_6): Likewise.
+       * sysdeps/unix/sysv/linux/hppa/sysdep.h (SAVE_PIC): Don't mention
+       copy of PIC register.
+       (LOAD_PIC): Likewise don't mention restore.
+       (DO_CALL): Fix CFA offset.  Use .cfi_def_cfa_offset instead of
+       .cfi_offset.  Don't record stack pointer offset.  Correct PIC register
+       offset.  Don't mention frame related instructions in epilogue.
+
+       [BZ 20098]
+       * sysdeps/hppa/dl-fptr.c (_dl_read_access_allowed): New.
+       (_dl_lookup_address): Return address if it is not consistent with
+       being a linker defined function pointer.  Likewise, return address
+       if address and function descriptor addresses are not accessible.
+
+       [BZ locale/19838]
+       * sysdeps/unix/sysv/linux/hppa/bits/shm.h (SHMLBA): Set to page size.
+
+       * nptl/allocatestack.c (allocate_stack): Align old and new guard
+       addresses to page boundaries when the stack grows up.
+
+       * sysdeps/hppa/math-tests.h: New.
+
+       [BZ #21016]
+       * sysdeps/hppa/nptl/bits/pthreadtypes.h: Update pthread_cond_t typedef.
+       * sysdeps/unix/sysv/linux/hppa/pthread.h: Include
+       bits/types/struct_timespec.h.
+       (PTHREAD_MUTEX_INITIALIZER): Revise define.
+       (PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP): Likewise.
+       (PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP): Likewise.
+       (PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP): Likewise.
+       (PTHREAD_RWLOCK_INITIALIZER): Likewise.
+       (PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP): Likewise.
+       (PTHREAD_COND_INITIALIZER): Likewise.
+       Remove old definitions.
+       * sysdeps/unix/sysv/linux/hppa/internaltypes.h: Delete.
+       * sysdeps/unix/sysv/linux/hppa/pthread_cond_broadcast.c: Delete.
+       * sysdeps/unix/sysv/linux/hppa/pthread_cond_destroy.c: Delete.
+       * sysdeps/unix/sysv/linux/hppa/pthread_cond_init.c: Delete.
+       * sysdeps/unix/sysv/linux/hppa/pthread_cond_signal.c: Delete.
+       * sysdeps/unix/sysv/linux/hppa/pthread_cond_wait.c: Delete.
+
+2017-08-11  Florian Weimer  <fweimer@redhat.com>
+
+       [BZ #21242]
+       * assert/assert.h [__GNUC__ && !__STRICT_ANSI__] (assert):
+       Suppress pedantic warning resulting from statement expression.
+       (__ASSERT_FUNCTION): Add missing __extension__.
+
+2017-08-08  Helge Deller  <deller@gmx.de>
+
+       [BZ #21049]
+        * sysdeps/hppa/__longjmp.c (__longjmp): Move call to CHECK_SP up
+        to avoid clobbering r26.
+
+2017-08-06  H.J. Lu  <hongjiu.lu@intel.com>
+
+       [BZ #21871]
+       * sysdeps/x86/cpu-features.c (init_cpu_features): Set
+       bit_arch_Use_dl_runtime_resolve_opt only with AVX512F.
+
+2017-08-04  Aurelien Jarno  <aurelien@aurel32.net>
+
+       * sysdeps/i386/i686/fpu/multiarch/libm-test-ulps: Regenerated.
+
+2017-08-03  Aurelien Jarno  <aurelien@aurel32.net>
+
+       * stdlib/getentropy.c (getentropy): Change return type to int.
+
+2017-04-28  Tulio Magno Quites Machado Filho  <tuliom@linux.vnet.ibm.com>
+
+       [BZ #21280]
+       * sysdeps/powerpc/power7/fpu/s_logbl.c (__logbl): Ignore the
+       signal of subnormals and adjust the exponent of power of 2 down
+       when low part has opposite sign.
+
+2017-07-26  H.J. Lu  <hongjiu.lu@intel.com>
+
+       [BZ #21666]
+       * misc/regexp.c (loc1): Add __attribute__ ((nocommon));
+       (loc2): Likewise.
+       (locs): Likewise.
+
+2017-07-12  Szabolcs Nagy  <szabolcs.nagy@arm.com>
+
+       * sysdeps/aarch64/dl-machine.h (RTLD_START_1): Change _dl_argv to the
+       hidden __GI__dl_argv symbol.
+
+2017-07-06  Florian Weimer  <fweimer@redhat.com>
+           H.J. Lu  <hongjiu.lu@intel.com>
+
+       [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  <fweimer@redhat.com>
+
+       * sysdeps/i386/i686/multiarch/strcspn-c.c: Add IS_IN (libc) guard.
+       * sysdeps/i386/i686/multiarch/varshift.c: Likewise.
+
+2017-03-07  Siddhesh Poyarekar  <siddhesh@sourceware.org>
+
+       [BZ #21209]
+       * elf/rtld.c (process_envvars): Ignore LD_HWCAP_MASK for
+       AT_SECURE processes.
+       * sysdeps/generic/unsecvars.h: Add LD_HWCAP_MASK.
+       * elf/tst-env-setuid.c (test_parent): Test LD_HWCAP_MASK.
+       (test_child): Likewise.
+       * elf/Makefile (tst-env-setuid-ENV): Add LD_HWCAP_MASK.
+
+2017-06-19  Florian Weimer  <fweimer@redhat.com>
+
+       * 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  <fweimer@redhat.com>
+
+       * 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  <fweimer@redhat.com>
+
+       [BZ #21624]
+       CVE-2017-1000366
+       * elf/rtld.c (process_envvars): Ignore LD_LIBRARY_PATH for
+       __libc_enable_secure.
+
+2017-05-12  Florian Weimer  <fweimer@redhat.com>
+
+       [BZ #21386]
+       * sysdeps/nptl/fork.c (__libc_fork): Remove assertions on the
+       parent PID.  The assertion in the child is incorrect with PID
+       namespaces.
+
+2017-03-15  Joseph Myers  <joseph@codesourcery.com>
+
+       * sysdeps/x86/fpu/test-math-vector-sincos.h (INIT_VEC_PTRS_LOOP):
+       Use a union when storing pointers.
+       (VECTOR_WRAPPER_fFF_2): Do not take address of integer vector and
+       cast result when passing to INIT_VEC_PTRS_LOOP.
+       (VECTOR_WRAPPER_fFF_3): Likewise.
+       (VECTOR_WRAPPER_fFF_4): Likewise.
+
+2017-05-01  Adhemerval Zanella  <adhemerval.zanella@linaro.org>
+
+       [BZ# 21182]
+       * string/test-memchr.c (do_test): Add BZ#21182 checks for address
+       near end of a page.
+       * sysdeps/i386/i686/multiarch/memchr-sse2.S (__memchr): Fix
+       overflow calculation.
+
+2017-04-28  H.J. Lu  <hongjiu.lu@intel.com>
+
+       [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  <hongjiu.lu@intel.com>
+
+       * sysdeps/x86/cpu-features.c (init_cpu_features): Set
+       Prefer_No_VZEROUPPER if AVX512ER is available.
+       * sysdeps/x86/cpu-features.h
+       (bit_cpu_AVX512PF): New.
+       (bit_cpu_AVX512ER): Likewise.
+       (bit_cpu_AVX512CD): Likewise.
+       (bit_cpu_AVX512BW): Likewise.
+       (bit_cpu_AVX512VL): Likewise.
+       (index_cpu_AVX512PF): Likewise.
+       (index_cpu_AVX512ER): Likewise.
+       (index_cpu_AVX512CD): Likewise.
+       (index_cpu_AVX512BW): Likewise.
+       (index_cpu_AVX512VL): Likewise.
+       (reg_AVX512PF): Likewise.
+       (reg_AVX512ER): Likewise.
+       (reg_AVX512CD): Likewise.
+       (reg_AVX512BW): Likewise.
+       (reg_AVX512VL): Likewise.
+
+2017-04-11  Adhemerval Zanella  <adhemerval.zanella@linaro.org>
+
+       * posix/globtest.sh: Add cleanup routine on trap 0.
+
+2017-04-07  H.J. Lu  <hongjiu.lu@intel.com>
+
+       [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  <vapier@gentoo.org>
+
+       [BZ #21253]
+       * sysdeps/unix/sysv/linux/spawni.c (__spawnix): Increase argv_size
+       slack space by 32KiB.
+
+2017-04-03  Wladimir van der Laan  <laanwj@gmail.com>
+
+       [BZ# 21338]
+       * malloc/malloc.c: Call do_set_arena_max for M_ARENA_MAX
+       instead of incorrect do_set_arena_test
+
+2017-03-31  Slava Barinov  <v.barinov@samsung.com>
+
+       [BZ #21289]
+       * io/fts.h (fts_set): Replace __REDIRECT with __REDIRECT_NTH.
+
+2017-03-20  Mike Frysinger  <vapier@gentoo.org>
+
+       [BZ #21275]
+       * sysdeps/unix/sysv/linux/spawni.c [__ia64__] (CLONE): Rename
+       __stack to __stackbase.
+       (STACK): Invert _STACK_GROWS_DOWN and _STACK_GROWS_UP order of
+       checks so we can include defined(__ia64__) first.
+
+2017-03-15  Mike Frysinger  <vapier@gentoo.org>
+
+       * sysdeps/x86_64/mempcpy_chk.S (__mempcpy_chk): Check for SHARED
+       instead of PIC.
+
+2017-03-15  John David Anglin  <danglin@gcc.gnu.org>
+
+       * sysdeps/hppa/dl-machine.h (DL_STACK_END): Define.
+       (RTLD_START): Don't record stack end address in _dl_start_user.
+
+2017-03-02  Florian Weimer  <fweimer@redhat.com>
+
+       [BZ #21015]
+       * manual/install.texi (Configuring and compiling): Document
+       --enable-bind-now.
+       * Makeconfig [bind-now] (LDFLAGS-lib.so): Set.
+       (build-shlib-helper): Use $(LDFLAGS-lib.so).
+       (format.lds): Likewise.
+       [bind-now] (LDFLAGS-c.so): Remove.
+       * sysdeps/x86_64/localplt.data (libm.so): matherr relocation can
+       be R_X86_64_GLOB_DAT.
+       * sysdeps/unix/sysv/linux/i386/localplt.data (libm.so): matherr
+       relocation can be R_386_GLOB_DAT.
+       * sysdeps/unix/sysv/linux/alpha/localplt.data (libm.so): matherr
+       relocaiton can be R_ALPHA_GLOB_DAT.
+       * iconvdata/Makefile [bind-now] (LDFLAGS.so): Add -Wl,-z,now.
+
+2017-02-28  Florian Weimer  <fweimer@redhat.com>
+
+       [BZ #20257]
+       * inet/Makefile (routines): Add deadline.
+       (tests-static): Add tst-deadline.
+       * inet/net-internal.h (struct deadline_current_time)
+       (__deadline_current_time, struct deadline, __deadline_is_infinite)
+       (__deadline_elapsed, __deadline_first, __deadline_from_timeval)
+       (__deadline_to_ms, __is_timeval_valid_timeout): Declare.
+       * inet/deadline.c: New file.
+       * inet/tst-deadline.c: Likewise.
+       * sunrpc/Makefile (tests): Add tst-udp-nonblocking,
+       tst-udp-timeout, tst-udp-garbage.
+       (tst-udp-nonblocking, tst-udp-timeout): Link against libc.so
+       explicitly.
+       (tst-udp-garbage): Likewise.  Also link against thread library.
+       * sunrpc/clnt_udp.c (struct cu_data): Mention in comment that the
+       struct layout is part of the ABI.
+       (clntudp_call): Rework timeout handling.
+       * sunrpc/tst-udp-garbage.c: New file.
+       * sunrpc/tst-udp-nonblocking.c: Likewise.
+       * sunrpc/tst-udp-timeout.c: Likewise.
+
+2017-02-27  Florian Weimer  <fweimer@redhat.com>
+
+       [BZ #21115]
+       * sunrpc/clnt_udp.c (clntudp_call): Free ancillary data later.
+       * sunrpc/Makefile (tests): Add tst-udp-error.
+       (tst-udp-error): Link against libc.so explicitly.
+       * sunrpc/tst-udp-error: New file.
+
+2017-02-08  Siddhesh Poyarekar  <siddhesh@sourceware.org>
+
+       [BZ #21109]
+       * elf/dl-tunable-types.h (tunable_callback_t): Accept
+       tunable_val_t as argument.
+       * elf/dl-tunables.c (__tunable_set_val): Add comment.
+       * malloc/arena.c (set_mallopt_check): Take tunable_val_t as
+       argument.
+       (DL_TUNABLE_CALLBACK_FNDECL): Likewise.
+
 2017-02-05  Siddhesh Poyarekar  <siddhesh@sourceware.org>
 
        * version.h (RELEASE): Set to "stable"
diff --git a/INSTALL b/INSTALL
index 3b3fd121b2329e7106474c4e1dfb9ce34a7d6ba3..e77cb2d4e2948891cd910a8ad17ac33d3c164e5c 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -146,6 +146,12 @@ will be used, and CFLAGS sets optimization options for the compiler.
      of routines called directly from assembler are excluded from this
      protection.
 
+'--enable-bind-now'
+     Disable lazy binding for installed shared objects.  This provides
+     additional security hardening because it enables full RELRO and a
+     read-only global offset table (GOT), at the cost of slightly
+     increased program load times.
+
 '--enable-pt_chown'
      The file 'pt_chown' is a helper binary for 'grantpt' (*note
      Pseudo-Terminals: Allocation.) that is installed setuid root to fix
index 97a15b569e52496cdf4da9265b664f0cd11a5def..1c815113b9d986d28b84c57a2514b94ee0023b79 100644 (file)
@@ -386,6 +386,13 @@ LDFLAGS.so += $(hashstyle-LDFLAGS)
 LDFLAGS-rtld += $(hashstyle-LDFLAGS)
 endif
 
+# If lazy relocations are disabled, add the -z now flag.  Use
+# LDFLAGS-lib.so instead of LDFLAGS.so, to avoid adding the flag to
+# test modules.
+ifeq ($(bind-now),yes)
+LDFLAGS-lib.so += -Wl,-z,now
+endif
+
 # Command to run after every final link (executable or shared object).
 # This is invoked with $(call after-link,...), so it should operate on
 # the file $1.  This can be set to do some sort of post-processing on
index e9194e54cf678a7c4643fc921274f5b36eaf881e..43343f03eee6cce08a1d55de1ebb90cc1a7b5a39 100644 (file)
--- a/Makerules
+++ b/Makerules
@@ -127,6 +127,14 @@ $(common-objpfx)cstdlib: $(c++-cstdlib-header)
 $(common-objpfx)cmath: $(c++-cmath-header)
        $(INSTALL_DATA) $< $@T
        $(move-if-change) $@T $@
+ifneq (,$(c++-bits-std_abs-h))
+# Also make a copy of <bits/std_abs.h> from GCC 7 to prevent it from
+# including /usr/include/stdlib.h.
+before-compile := $(common-objpfx)bits/std_abs.h $(before-compile)
+$(common-objpfx)bits/std_abs.h: $(c++-bits-std_abs-h)
+       $(INSTALL_DATA) $< $@T
+       $(move-if-change) $@T $@
+endif
 endif
 
 before-compile := $(common-objpfx)libc-abis.h $(before-compile)
@@ -588,7 +596,7 @@ $(LINK.o) -shared -static-libgcc -Wl,-O1 $(sysdep-LDFLAGS) \
          $(extra-B-$(@F:lib%.so=%).so) -B$(csu-objpfx) \
          $(extra-B-$(@F:lib%.so=%).so) $(load-map-file) \
          -Wl,-soname=lib$(libprefix)$(@F:lib%.so=%).so$($(@F)-version) \
-         $(LDFLAGS.so) $(LDFLAGS-$(@F:lib%.so=%).so) \
+         $(LDFLAGS.so) $(LDFLAGS-lib.so) $(LDFLAGS-$(@F:lib%.so=%).so) \
          -L$(subst :, -L,$(rpath-link)) -Wl,-rpath-link=$(rpath-link)
 endef
 
@@ -669,14 +677,17 @@ $(build-module-helper) -o $@ $(shlib-lds-flags) \
 $(call after-link,$@)
 endef
 
+# sofini.os must be placed last since it terminates .eh_frame section.
 build-module-helper-objlist = \
        $(patsubst %_pic.a,$(whole-archive) %_pic.a $(no-whole-archive),\
                   $(filter-out %.lds $(map-file) $(+preinit) $(+postinit) \
+                               $(elf-objpfx)sofini.os \
                                $(link-libc-deps),$^))
 
 build-module-objlist = $(build-module-helper-objlist) $(LDLIBS-$(@F:%.so=%).so)
 build-shlib-objlist = $(build-module-helper-objlist) \
-                     $(LDLIBS-$(@F:lib%.so=%).so)
+                     $(LDLIBS-$(@F:lib%.so=%).so) \
+                     $(filter $(elf-objpfx)sofini.os,$^)
 
 # Don't try to use -lc when making libc.so itself.
 # Also omits crti.o and crtn.o, which we do not want
@@ -686,10 +697,6 @@ LDFLAGS-c.so = -nostdlib -nostartfiles
 LDLIBS-c.so += $(libc.so-gnulib)
 # Give libc.so an entry point and make it directly runnable itself.
 LDFLAGS-c.so += -e __libc_main
-# If lazy relocation is disabled add the -z now flag.
-ifeq ($(bind-now),yes)
-LDFLAGS-c.so += -Wl,-z,now
-endif
 # Pre-link the objects of libc_pic.a so that we can locally resolve
 # COMMON symbols before we link against ld.so.  This is because ld.so
 # contains some of libc_pic.a already, which will prevent the COMMONs
@@ -1104,7 +1111,8 @@ $(common-objpfx)format.lds: $(..)scripts/output-format.sed \
 ifneq (unknown,$(output-format))
        echo > $@.new 'OUTPUT_FORMAT($(output-format))'
 else
-       $(LINK.o) -shared $(sysdep-LDFLAGS) $(rtld-LDFLAGS) $(LDFLAGS.so) \
+       $(LINK.o) -shared $(sysdep-LDFLAGS) $(rtld-LDFLAGS) \
+                 $(LDFLAGS.so) $(LDFLAGS-lib.so) \
                  -x c /dev/null -o $@.so -Wl,--verbose -v 2>&1 \
        | sed -n -f $< > $@.new
        test -s $@.new
diff --git a/NEWS b/NEWS
index ec15dde7613306cfa574149f61ea38ab3fbba76d..0a8f20e37111acdced23d6aab9e7cb4fd14693d5 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,47 @@ See the end for copying conditions.
 
 Please send GNU C library bug reports via <http://sourceware.org/bugzilla/>
 using `glibc' in the "product" field.
+\f
+Version 2.25.1
+
+Security related changes:
+
+* The DNS stub resolver limits the advertised UDP buffer size to 1200 bytes,
+  to avoid fragmentation-based spoofing attacks.
+
+  CVE-2017-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.
+
+The following bugs are resolved with this release:
+
+  [20257] sunrpc: clntudp_call does not enforce timeout when receiving data
+  [21015] Document and fix --enable-bind-now
+  [21109] Tunables broken on big-endian
+  [21115] sunrpc: Use-after-free in error path in clntudp_call
+  [21209] Ignore and remove LD_HWCAP_MASK for AT_SECURE programs
+  [21242] assert: Suppress pedantic warning caused by statement expression
+  [21265] x86-64: Use fxsave/xsave/xsavec in _dl_runtime_resolve
+  [21289] Fix symbol redirect for fts_set
+  [21298] rwlock can deadlock on frequent reader/writer phase switching
+  [21386] Assertion in fork for distinct parent PID is incorrect
+  [21624] Unsafe alloca allows local attackers to alias stack and heap (CVE-2017-1000366)
+  [21654] nss: Fix invalid cast in group merging
+  [21778] Robust mutex may deadlock
+  [21972] assert macro requires operator== (int) for its argument type
+  [22322] libc: [mips64] wrong bits/long-double.h installed
+
+Security related changes:
+
+  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).
+
 \f
 Version 2.25
 
index 1c3be9b01fdba377b10b157c67431632e28916d5..9ec1be81a95631c859eb9b68d46709661201e923 100644 (file)
@@ -25,6 +25,15 @@ include ../Makeconfig
 headers        := assert.h
 
 routines := assert assert-perr __assert
-tests := test-assert test-assert-perr
+tests := test-assert test-assert-perr tst-assert-c++ tst-assert-g++
 
 include ../Rules
+
+ifeq ($(have-cxx-thread_local),yes)
+CFLAGS-tst-assert-c++.o = -std=c++11
+LDLIBS-tst-assert-c++ = -lstdc++
+CFLAGS-tst-assert-g++.o = -std=gnu++11
+LDLIBS-tst-assert-g++ = -lstdc++
+else
+tests-unsupported += tst-assert-c++ tst-assert-g++
+endif
index 22f019537cea4d15fa4e915eb7989d7bf4bc3d2f..640c95c06344ffbf1971793e8aaf283aad6679e2 100644 (file)
@@ -85,19 +85,29 @@ __END_DECLS
 /* When possible, define assert so that it does not add extra
    parentheses around EXPR.  Otherwise, those added parentheses would
    suppress warnings we'd expect to be detected by gcc's -Wparentheses.  */
-# if !defined __GNUC__ || defined __STRICT_ANSI__
+# if defined __cplusplus
+#  define assert(expr)                                                 \
+     (static_cast <bool> (expr)                                                \
+      ? void (0)                                                       \
+      : __assert_fail (#expr, __FILE__, __LINE__, __ASSERT_FUNCTION))
+# elif !defined __GNUC__ || defined __STRICT_ANSI__
 #  define assert(expr)                                                 \
     ((expr)                                                            \
      ? __ASSERT_VOID_CAST (0)                                          \
      : __assert_fail (#expr, __FILE__, __LINE__, __ASSERT_FUNCTION))
 # else
+/* The first occurrence of EXPR is not evaluated due to the sizeof,
+   but will trigger any pedantic warnings masked by the __extension__
+   for the second occurrence.  The ternary operator is required to
+   support function pointers and bit fields in this context, and to
+   suppress the evaluation of variable length arrays.  */
 #  define assert(expr)                                                 \
-    ({                                                                 \
+  ((void) sizeof ((expr) ? 1 : 0), __extension__ ({                    \
       if (expr)                                                                \
         ; /* empty */                                                  \
       else                                                             \
         __assert_fail (#expr, __FILE__, __LINE__, __ASSERT_FUNCTION);  \
-    })
+    }))
 # endif
 
 # ifdef        __USE_GNU
@@ -113,7 +123,7 @@ __END_DECLS
    C9x has a similar variable called __func__, but prefer the GCC one since
    it demangles C++ function names.  */
 # if defined __cplusplus ? __GNUC_PREREQ (2, 6) : __GNUC_PREREQ (2, 4)
-#   define __ASSERT_FUNCTION   __PRETTY_FUNCTION__
+#   define __ASSERT_FUNCTION   __extension__ __PRETTY_FUNCTION__
 # else
 #  if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
 #   define __ASSERT_FUNCTION   __func__
diff --git a/assert/tst-assert-c++.cc b/assert/tst-assert-c++.cc
new file mode 100644 (file)
index 0000000..12a5e69
--- /dev/null
@@ -0,0 +1,78 @@
+/* Tests for interactions between C++ and assert.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <assert.h>
+
+/* The C++ standard requires that if the assert argument is a constant
+   subexpression, then the assert itself is one, too.  */
+constexpr int
+check_constexpr ()
+{
+  return (assert (true), 1);
+}
+
+/* Objects of this class can be contextually converted to bool, but
+   cannot be compared to int.  */
+struct no_int
+{
+  no_int () = default;
+  no_int (const no_int &) = delete;
+
+  explicit operator bool () const
+  {
+    return true;
+  }
+
+  bool operator! () const; /* No definition.  */
+  template <class T> bool operator== (T) const; /* No definition.  */
+  template <class T> bool operator!= (T) const; /* No definition.  */
+};
+
+/* This class tests that operator== is not used by assert.  */
+struct bool_and_int
+{
+  bool_and_int () = default;
+  bool_and_int (const no_int &) = delete;
+
+  explicit operator bool () const
+  {
+    return true;
+  }
+
+  bool operator! () const; /* No definition.  */
+  template <class T> bool operator== (T) const; /* No definition.  */
+  template <class T> bool operator!= (T) const; /* No definition.  */
+};
+
+static int
+do_test ()
+{
+  {
+    no_int value;
+    assert (value);
+  }
+
+  {
+    bool_and_int value;
+    assert (value);
+  }
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/assert/tst-assert-g++.cc b/assert/tst-assert-g++.cc
new file mode 100644 (file)
index 0000000..8c06402
--- /dev/null
@@ -0,0 +1,19 @@
+/* Tests for interactions between C++ and assert.  GNU C++11 version.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <tst-assert-c++.cc>
index 5836b32a7203cc5daa50e35fb46d772f0c60590b..709527da4ff6ea495e7b1bd4a9e0e9082c274cab 100644 (file)
@@ -47,6 +47,7 @@ sysincludes = @SYSINCLUDES@
 c++-sysincludes = @CXX_SYSINCLUDES@
 c++-cstdlib-header = @CXX_CSTDLIB_HEADER@
 c++-cmath-header = @CXX_CMATH_HEADER@
+c++-bits-std_abs-h = @CXX_BITS_STD_ABS_H@
 all-warnings = @all_warnings@
 enable-werror = @enable_werror@
 
index eecd0ace740e8fafcb01c0019bc592fe1469b609..ee637a7caf98e329b404506bad0e09c5e3cd4dc6 100755 (executable)
--- a/configure
+++ b/configure
@@ -634,6 +634,7 @@ BISON
 INSTALL_INFO
 PERL
 BASH_SHELL
+CXX_BITS_STD_ABS_H
 CXX_CMATH_HEADER
 CXX_CSTDLIB_HEADER
 CXX_SYSINCLUDES
@@ -5318,14 +5319,17 @@ fi
 # copy of those headers in Makerules.
 if test -n "$CXX"; then
   find_cxx_header () {
-    echo "#include <$1>" | $CXX -M -MP -x c++ - | sed -n "/$1:/{s/:\$//;p}"
+    echo "#include <$1>" | $CXX -M -MP -x c++ - 2>/dev/null \
+        | sed -n "\,$1:,{s/:\$//;p}"
   }
   CXX_CSTDLIB_HEADER="$(find_cxx_header cstdlib)"
   CXX_CMATH_HEADER="$(find_cxx_header cmath)"
+  CXX_BITS_STD_ABS_H="$(find_cxx_header bits/std_abs.h)"
 fi
 
 
 
+
 # Test if LD_LIBRARY_PATH contains the notation for the current directory
 # since this would lead to problems installing/building glibc.
 # LD_LIBRARY_PATH contains the current directory if one of the following
index 4a77411b71949771233cea4b525f95bf446f3dc1..d288ff43cdcb2f17b1ef50d9016ee23a1fafd167 100644 (file)
@@ -1176,13 +1176,16 @@ AC_SUBST(CXX_SYSINCLUDES)
 # copy of those headers in Makerules.
 if test -n "$CXX"; then
   find_cxx_header () {
-    echo "#include <$1>" | $CXX -M -MP -x c++ - | sed -n "/$1:/{s/:\$//;p}"
+    echo "#include <$1>" | $CXX -M -MP -x c++ - 2>/dev/null \
+        | sed -n "\,$1:,{s/:\$//;p}"
   }
   CXX_CSTDLIB_HEADER="$(find_cxx_header cstdlib)"
   CXX_CMATH_HEADER="$(find_cxx_header cmath)"
+  CXX_BITS_STD_ABS_H="$(find_cxx_header bits/std_abs.h)"
 fi
 AC_SUBST(CXX_CSTDLIB_HEADER)
 AC_SUBST(CXX_CMATH_HEADER)
+AC_SUBST(CXX_BITS_STD_ABS_H)
 
 # Test if LD_LIBRARY_PATH contains the notation for the current directory
 # since this would lead to problems installing/building glibc.
index 61abeb59eeef0b9ed8e4998b1f28cc1310073644..cc4aeb25b6128cb23ed7fa032c066310a0a9db6c 100644 (file)
@@ -1398,6 +1398,7 @@ $(objpfx)tst-nodelete-dlclose: $(objpfx)tst-nodelete-dlclose-dso.so
 $(objpfx)tst-nodelete-dlclose.out: $(objpfx)tst-nodelete-dlclose-dso.so \
                                   $(objpfx)tst-nodelete-dlclose-plugin.so
 
-tst-env-setuid-ENV = MALLOC_CHECK_=2 MALLOC_MMAP_THRESHOLD_=4096
+tst-env-setuid-ENV = MALLOC_CHECK_=2 MALLOC_MMAP_THRESHOLD_=4096 \
+                    LD_HWCAP_MASK=0xffffffff
 tst-env-setuid-tunables-ENV = \
        GLIBC_TUNABLES=glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096
index a986f0b5930d8aba0aac86560bea3d863ed0da5b..37a4e8021f8f1d4d1f3d5f0b7a0a4093dfe7f88c 100644 (file)
@@ -21,8 +21,6 @@
 # define _TUNABLE_TYPES_H_
 #include <stddef.h>
 
-typedef void (*tunable_callback_t) (void *);
-
 typedef enum
 {
   TUNABLE_TYPE_INT_32,
@@ -43,6 +41,8 @@ typedef union
   const char *strval;
 } tunable_val_t;
 
+typedef void (*tunable_callback_t) (tunable_val_t *);
+
 /* Security level for tunables.  This decides what to do with individual
    tunables for AT_SECURE binaries.  */
 typedef enum
index a8d53d6a311d4f532608b4805979c01180c03be2..e42aa670033131f75a682aedf492c017f2bcb673 100644 (file)
@@ -455,6 +455,8 @@ __tunable_set_val (tunable_id_t id, void *valp, tunable_callback_t callback)
   if (cur->strval == NULL)
     return;
 
+  /* Caller does not need the value, just call the callback with our tunable
+     value.  */
   if (valp == NULL)
     goto cb;
 
index a036ece9568957f125a482209f6342d77313a171..9362a21e73ac40851bce67ca388c50af7305c1c1 100644 (file)
@@ -99,14 +99,121 @@ uintptr_t __pointer_chk_guard_local
 strong_alias (__pointer_chk_guard_local, __pointer_chk_guard)
 #endif
 
+/* Length limits for names and paths, to protect the dynamic linker,
+   particularly when __libc_enable_secure is active.  */
+#ifdef NAME_MAX
+# define SECURE_NAME_LIMIT NAME_MAX
+#else
+# define SECURE_NAME_LIMIT 255
+#endif
+#ifdef PATH_MAX
+# define SECURE_PATH_LIMIT PATH_MAX
+#else
+# define SECURE_PATH_LIMIT 1024
+#endif
+
+/* Check that AT_SECURE=0, or that the passed name does not contain
+   directories and is not overly long.  Reject empty names
+   unconditionally.  */
+static bool
+dso_name_valid_for_suid (const char *p)
+{
+  if (__glibc_unlikely (__libc_enable_secure))
+    {
+      /* Ignore pathnames with directories for AT_SECURE=1
+        programs, and also skip overlong names.  */
+      size_t len = strlen (p);
+      if (len >= SECURE_NAME_LIMIT || memchr (p, '/', len) != NULL)
+       return false;
+    }
+  return *p != '\0';
+}
 
-/* List of auditing DSOs.  */
+/* LD_AUDIT variable contents.  Must be processed before the
+   audit_list below.  */
+const char *audit_list_string;
+
+/* Cyclic list of auditing DSOs.  audit_list->next is the first
+   element.  */
 static struct audit_list
 {
   const char *name;
   struct audit_list *next;
 } *audit_list;
 
+/* Iterator for audit_list_string followed by audit_list.  */
+struct audit_list_iter
+{
+  /* Tail of audit_list_string still needing processing, or NULL.  */
+  const char *audit_list_tail;
+
+  /* The list element returned in the previous iteration.  NULL before
+     the first element.  */
+  struct audit_list *previous;
+
+  /* Scratch buffer for returning a name which is part of
+     audit_list_string.  */
+  char fname[SECURE_NAME_LIMIT];
+};
+
+/* Initialize an audit list iterator.  */
+static void
+audit_list_iter_init (struct audit_list_iter *iter)
+{
+  iter->audit_list_tail = audit_list_string;
+  iter->previous = NULL;
+}
+
+/* Iterate through both audit_list_string and audit_list.  */
+static const char *
+audit_list_iter_next (struct audit_list_iter *iter)
+{
+  if (iter->audit_list_tail != NULL)
+    {
+      /* First iterate over audit_list_string.  */
+      while (*iter->audit_list_tail != '\0')
+       {
+         /* Split audit list at colon.  */
+         size_t len = strcspn (iter->audit_list_tail, ":");
+         if (len > 0 && len < sizeof (iter->fname))
+           {
+             memcpy (iter->fname, iter->audit_list_tail, len);
+             iter->fname[len] = '\0';
+           }
+         else
+           /* Do not return this name to the caller.  */
+           iter->fname[0] = '\0';
+
+         /* Skip over the substring and the following delimiter.  */
+         iter->audit_list_tail += len;
+         if (*iter->audit_list_tail == ':')
+           ++iter->audit_list_tail;
+
+         /* If the name is valid, return it.  */
+         if (dso_name_valid_for_suid (iter->fname))
+           return iter->fname;
+         /* Otherwise, wrap around and try the next name.  */
+       }
+      /* Fall through to the procesing of audit_list.  */
+    }
+
+  if (iter->previous == NULL)
+    {
+      if (audit_list == NULL)
+       /* No pre-parsed audit list.  */
+       return NULL;
+      /* Start of audit list.  The first list element is at
+        audit_list->next (cyclic list).  */
+      iter->previous = audit_list->next;
+      return iter->previous->name;
+    }
+  if (iter->previous == audit_list)
+    /* Cyclic list wrap-around.  */
+    return NULL;
+  iter->previous = iter->previous->next;
+  return iter->previous->name;
+}
+
 #ifndef HAVE_INLINED_SYSCALLS
 /* Set nonzero during loading and initialization of executable and
    libraries, cleared before the executable's entry point runs.  This
@@ -716,6 +823,42 @@ static const char *preloadlist attribute_relro;
 /* Nonzero if information about versions has to be printed.  */
 static int version_info attribute_relro;
 
+/* The LD_PRELOAD environment variable gives list of libraries
+   separated by white space or colons that are loaded before the
+   executable's dependencies and prepended to the global scope list.
+   (If the binary is running setuid all elements containing a '/' are
+   ignored since it is insecure.)  Return the number of preloads
+   performed.  */
+unsigned int
+handle_ld_preload (const char *preloadlist, struct link_map *main_map)
+{
+  unsigned int npreloads = 0;
+  const char *p = preloadlist;
+  char fname[SECURE_PATH_LIMIT];
+
+  while (*p != '\0')
+    {
+      /* Split preload list at space/colon.  */
+      size_t len = strcspn (p, " :");
+      if (len > 0 && len < sizeof (fname))
+       {
+         memcpy (fname, p, len);
+         fname[len] = '\0';
+       }
+      else
+       fname[0] = '\0';
+
+      /* Skip over the substring and the following delimiter.  */
+      p += len;
+      if (*p != '\0')
+       ++p;
+
+      if (dso_name_valid_for_suid (fname))
+       npreloads += do_preload (fname, main_map, "LD_PRELOAD");
+    }
+  return npreloads;
+}
+
 static void
 dl_main (const ElfW(Phdr) *phdr,
         ElfW(Word) phnum,
@@ -1238,11 +1381,13 @@ of this helper program; chances are you did not intend to run this program.\n\
     GL(dl_rtld_map).l_tls_modid = _dl_next_tls_modid ();
 
   /* If we have auditing DSOs to load, do it now.  */
-  if (__glibc_unlikely (audit_list != NULL))
+  bool need_security_init = true;
+  if (__glibc_unlikely (audit_list != NULL)
+      || __glibc_unlikely (audit_list_string != NULL))
     {
-      /* Iterate over all entries in the list.  The order is important.  */
       struct audit_ifaces *last_audit = NULL;
-      struct audit_list *al = audit_list->next;
+      struct audit_list_iter al_iter;
+      audit_list_iter_init (&al_iter);
 
       /* Since we start using the auditing DSOs right away we need to
         initialize the data structures now.  */
@@ -1253,9 +1398,14 @@ of this helper program; chances are you did not intend to run this program.\n\
         use different values (especially the pointer guard) and will
         fail later on.  */
       security_init ();
+      need_security_init = false;
 
-      do
+      while (true)
        {
+         const char *name = audit_list_iter_next (&al_iter);
+         if (name == NULL)
+           break;
+
          int tls_idx = GL(dl_tls_max_dtv_idx);
 
          /* Now it is time to determine the layout of the static TLS
@@ -1264,7 +1414,7 @@ of this helper program; chances are you did not intend to run this program.\n\
             no DF_STATIC_TLS bit is set.  The reason is that we know
             glibc will use the static model.  */
          struct dlmopen_args dlmargs;
-         dlmargs.fname = al->name;
+         dlmargs.fname = name;
          dlmargs.map = NULL;
 
          const char *objname;
@@ -1277,7 +1427,7 @@ of this helper program; chances are you did not intend to run this program.\n\
            not_loaded:
              _dl_error_printf ("\
 ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
-                               al->name, err_str);
+                               name, err_str);
              if (malloced)
                free ((char *) err_str);
            }
@@ -1381,10 +1531,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
                  goto not_loaded;
                }
            }
-
-         al = al->next;
        }
-      while (al != audit_list->next);
 
       /* If we have any auditing modules, announce that we already
         have two objects loaded.  */
@@ -1462,23 +1609,8 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
 
   if (__glibc_unlikely (preloadlist != NULL))
     {
-      /* The LD_PRELOAD environment variable gives list of libraries
-        separated by white space or colons that are loaded before the
-        executable's dependencies and prepended to the global scope
-        list.  If the binary is running setuid all elements
-        containing a '/' are ignored since it is insecure.  */
-      char *list = strdupa (preloadlist);
-      char *p;
-
       HP_TIMING_NOW (start);
-
-      /* Prevent optimizing strsep.  Speed is not important here.  */
-      while ((p = (strsep) (&list, " :")) != NULL)
-       if (p[0] != '\0'
-           && (__builtin_expect (! __libc_enable_secure, 1)
-               || strchr (p, '/') == NULL))
-         npreloads += do_preload (p, main_map, "LD_PRELOAD");
-
+      npreloads += handle_ld_preload (preloadlist, main_map);
       HP_TIMING_NOW (stop);
       HP_TIMING_DIFF (diff, start, stop);
       HP_TIMING_ACCUM_NT (load_time, diff);
@@ -1663,7 +1795,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
   if (tcbp == NULL)
     tcbp = init_tls ();
 
-  if (__glibc_likely (audit_list == NULL))
+  if (__glibc_likely (need_security_init))
     /* Initialize security features.  But only if we have not done it
        earlier.  */
     security_init ();
@@ -2294,9 +2426,7 @@ process_dl_audit (char *str)
   char *p;
 
   while ((p = (strsep) (&str, ":")) != NULL)
-    if (p[0] != '\0'
-       && (__builtin_expect (! __libc_enable_secure, 1)
-           || strchr (p, '/') == NULL))
+    if (dso_name_valid_for_suid (p))
       {
        /* This is using the local malloc, not the system malloc.  The
           memory can never be freed.  */
@@ -2360,7 +2490,7 @@ process_envvars (enum mode *modep)
              break;
            }
          if (memcmp (envline, "AUDIT", 5) == 0)
-           process_dl_audit (&envline[6]);
+           audit_list_string = &envline[6];
          break;
 
        case 7:
@@ -2404,7 +2534,8 @@ process_envvars (enum mode *modep)
 
        case 10:
          /* Mask for the important hardware capabilities.  */
-         if (memcmp (envline, "HWCAP_MASK", 10) == 0)
+         if (!__libc_enable_secure
+             && memcmp (envline, "HWCAP_MASK", 10) == 0)
            GLRO(dl_hwcap_mask) = __strtoul_internal (&envline[11], NULL,
                                                      0, 0);
          break;
@@ -2418,7 +2549,8 @@ process_envvars (enum mode *modep)
 
        case 12:
          /* The library search path.  */
-         if (memcmp (envline, "LIBRARY_PATH", 12) == 0)
+         if (!__libc_enable_secure
+             && memcmp (envline, "LIBRARY_PATH", 12) == 0)
            {
              library_path = &envline[13];
              break;
index 6ec3fa587449c6f93e9cf5ca06951851dc35cabf..eec408eb5db6f371cc67f4e40ae67160fd032dfd 100644 (file)
@@ -213,6 +213,12 @@ test_child (void)
       return 1;
     }
 
+  if (getenv ("LD_HWCAP_MASK") != NULL)
+    {
+      printf ("LD_HWCAP_MASK still set\n");
+      return 1;
+    }
+
   return 0;
 }
 #endif
@@ -233,6 +239,12 @@ test_parent (void)
       return 1;
     }
 
+  if (getenv ("LD_HWCAP_MASK") == NULL)
+    {
+      printf ("LD_HWCAP_MASK lost\n");
+      return 1;
+    }
+
   return 0;
 }
 #endif
index 77c494d15958975671e5458859c3ed55567ed801..035e7a604bbb71e0c3b282f62e847d43a03ed85e 100644 (file)
@@ -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];
index 04157b25c5ccc64d81a8b5a019714a2bce65f48c..e4845871f559b406d3d5d01138a09d82df6178b3 100644 (file)
@@ -63,6 +63,11 @@ modules      := ISO8859-1 ISO8859-2 ISO8859-3 ISO8859-4 ISO8859-5             \
           MAC-CENTRALEUROPE KOI8-RU ISO8859-9E                          \
           CP770 CP771 CP772 CP773 CP774
 
+# If lazy binding is disabled, use BIND_NOW for the gconv modules.
+ifeq ($(bind-now),yes)
+LDFLAGS.so += -Wl,-z,now
+endif
+
 modules.so := $(addsuffix .so, $(modules))
 
 ifeq (yes,$(build-shared))
index 95dcd3ca37ce7eca0e14237824684eb1fe35ae41..e8f477cd86b7be11121e5f3ca8a7b5ac8c146ca2 100644 (file)
@@ -37,8 +37,6 @@ extern void res_pquery (const res_state __statp, const unsigned char *__msg,
 extern int res_ourserver_p (const res_state __statp,
                            const struct sockaddr_in6 *__inp);
 extern void __res_iclose (res_state statp, bool free_addr);
-extern int __res_nopt(res_state statp, int n0, unsigned char *buf, int buflen,
-                     int anslen);
 libc_hidden_proto (__res_ninit)
 libc_hidden_proto (__res_maybe_init)
 libc_hidden_proto (__res_nclose)
@@ -91,7 +89,6 @@ libresolv_hidden_proto (__res_nameinquery)
 libresolv_hidden_proto (__res_queriesmatch)
 libresolv_hidden_proto (__res_nsend)
 libresolv_hidden_proto (__b64_ntop)
-libresolv_hidden_proto (__res_nopt)
 libresolv_hidden_proto (__dn_count_labels)
 libresolv_hidden_proto (__p_secstodate)
 
index 010792af8f3dc0aab072df6e4a0e8cd610405cb2..6a7d3e0664168810a15a3f54fb588e20f67c573b 100644 (file)
@@ -45,14 +45,18 @@ routines := htonl htons             \
            in6_addr getnameinfo if_index ifaddrs inet6_option \
            getipv4sourcefilter setipv4sourcefilter \
            getsourcefilter setsourcefilter inet6_opt inet6_rth \
-           inet6_scopeid_pton
+           inet6_scopeid_pton deadline
 
 aux := check_pf check_native ifreq
 
 tests := htontest test_ifindex tst-ntoa tst-ether_aton tst-network \
         tst-gethnm test-ifaddrs bug-if1 test-inet6_opt tst-ether_line \
         tst-getni1 tst-getni2 tst-inet6_rth tst-checks tst-checks-posix \
-        tst-sockaddr tst-inet6_scopeid_pton test-hnto-types
+        tst-sockaddr tst-inet6_scopeid_pton test-hnto-types tst-deadline
+
+# tst-deadline must be linked statically so that we can access
+# internal functions.
+tests-static += tst-deadline
 
 include ../Rules
 
diff --git a/inet/deadline.c b/inet/deadline.c
new file mode 100644 (file)
index 0000000..c1fa415
--- /dev/null
@@ -0,0 +1,122 @@
+/* Computing deadlines for timeouts.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <net-internal.h>
+
+#include <assert.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <time.h>
+
+struct deadline_current_time internal_function
+__deadline_current_time (void)
+{
+  struct deadline_current_time result;
+  if (__clock_gettime (CLOCK_MONOTONIC, &result.current) != 0)
+    {
+      struct timeval current_tv;
+      if (__gettimeofday (&current_tv, NULL) == 0)
+        __libc_fatal ("Fatal error: gettimeofday system call failed\n");
+      result.current.tv_sec = current_tv.tv_sec;
+      result.current.tv_nsec = current_tv.tv_usec * 1000;
+    }
+  assert (result.current.tv_sec >= 0);
+  return result;
+}
+
+/* A special deadline value for which __deadline_is_infinite is
+   true.  */
+static inline struct deadline
+infinite_deadline (void)
+{
+  return (struct deadline) { { -1, -1 } };
+}
+
+struct deadline internal_function
+__deadline_from_timeval (struct deadline_current_time current,
+                         struct timeval tv)
+{
+  assert (__is_timeval_valid_timeout (tv));
+
+  /* Compute second-based deadline.  Perform the addition in
+     uintmax_t, which is unsigned, to simply overflow detection.  */
+  uintmax_t sec = current.current.tv_sec;
+  sec += tv.tv_sec;
+  if (sec < (uintmax_t) tv.tv_sec)
+    return infinite_deadline ();
+
+  /* Compute nanosecond deadline.  */
+  int nsec = current.current.tv_nsec + tv.tv_usec * 1000;
+  if (nsec >= 1000 * 1000 * 1000)
+    {
+      /* Carry nanosecond overflow to seconds.  */
+      nsec -= 1000 * 1000 * 1000;
+      if (sec + 1 < sec)
+        return infinite_deadline ();
+      ++sec;
+    }
+  /* This uses a GCC extension, otherwise these casts for detecting
+     overflow would not be defined.  */
+  if ((time_t) sec < 0 || sec != (uintmax_t) (time_t) sec)
+    return infinite_deadline ();
+
+  return (struct deadline) { { sec, nsec } };
+}
+
+int internal_function
+__deadline_to_ms (struct deadline_current_time current,
+                  struct deadline deadline)
+{
+  if (__deadline_is_infinite (deadline))
+    return INT_MAX;
+
+  if (current.current.tv_sec > deadline.absolute.tv_sec
+      || (current.current.tv_sec == deadline.absolute.tv_sec
+          && current.current.tv_nsec >= deadline.absolute.tv_nsec))
+    return 0;
+  time_t sec = deadline.absolute.tv_sec - current.current.tv_sec;
+  if (sec >= INT_MAX)
+    /* This value will overflow below.  */
+    return INT_MAX;
+  int nsec = deadline.absolute.tv_nsec - current.current.tv_nsec;
+  if (nsec < 0)
+    {
+      /* Borrow from the seconds field.  */
+      assert (sec > 0);
+      --sec;
+      nsec += 1000 * 1000 * 1000;
+    }
+
+  /* Prepare for rounding up to milliseconds.  */
+  nsec += 999999;
+  if (nsec > 1000 * 1000 * 1000)
+    {
+      assert (sec < INT_MAX);
+      ++sec;
+      nsec -= 1000 * 1000 * 1000;
+    }
+
+  unsigned int msec = nsec / (1000 * 1000);
+  if (sec > INT_MAX / 1000)
+    return INT_MAX;
+  msec += sec * 1000;
+  if (msec > INT_MAX)
+    return INT_MAX;
+  return msec;
+}
index 087597ed9923f6db3ec087289483a6209ad440a0..2b2632c7ba845c7b3ea6d735f7e7451728f5c5b2 100644 (file)
 #define _NET_INTERNAL_H 1
 
 #include <arpa/inet.h>
+#include <stdbool.h>
 #include <stdint.h>
+#include <sys/time.h>
 
 int __inet6_scopeid_pton (const struct in6_addr *address,
                           const char *scope, uint32_t *result)
   internal_function attribute_hidden;
 libc_hidden_proto (__inet6_scopeid_pton)
 
+
+/* Deadline handling for enforcing timeouts.
+
+   Code should call __deadline_current_time to obtain the current time
+   and cache it locally.  The cache needs updating after every
+   long-running or potentially blocking operation.  Deadlines relative
+   to the current time can be computed using __deadline_from_timeval.
+   The deadlines may have to be recomputed in response to certain
+   events (such as an incoming packet), but they are absolute (not
+   relative to the current time).  A timeout suitable for use with the
+   poll function can be computed from such a deadline using
+   __deadline_to_ms.
+
+   The fields in the structs defined belowed should only be used
+   within the implementation.  */
+
+/* Cache of the current time.  Used to compute deadlines from relative
+   timeouts and vice versa.  */
+struct deadline_current_time
+{
+  struct timespec current;
+};
+
+/* Return the current time.  Terminates the process if the current
+   time is not available.  */
+struct deadline_current_time __deadline_current_time (void)
+  internal_function attribute_hidden;
+
+/* Computed absolute deadline.  */
+struct deadline
+{
+  struct timespec absolute;
+};
+
+
+/* For internal use only.  */
+static inline bool
+__deadline_is_infinite (struct deadline deadline)
+{
+  return deadline.absolute.tv_nsec < 0;
+}
+
+/* Return true if the current time is at the deadline or past it.  */
+static inline bool
+__deadline_elapsed (struct deadline_current_time current,
+                    struct deadline deadline)
+{
+  return !__deadline_is_infinite (deadline)
+    && (current.current.tv_sec > deadline.absolute.tv_sec
+        || (current.current.tv_sec == deadline.absolute.tv_sec
+            && current.current.tv_nsec >= deadline.absolute.tv_nsec));
+}
+
+/* Return the deadline which occurs first.  */
+static inline struct deadline
+__deadline_first (struct deadline left, struct deadline right)
+{
+  if (__deadline_is_infinite (right)
+      || left.absolute.tv_sec < right.absolute.tv_sec
+      || (left.absolute.tv_sec == right.absolute.tv_sec
+          && left.absolute.tv_nsec < right.absolute.tv_nsec))
+    return left;
+  else
+    return right;
+}
+
+/* Add TV to the current time and return it.  Returns a special
+   infinite absolute deadline on overflow.  */
+struct deadline __deadline_from_timeval (struct deadline_current_time,
+                                         struct timeval tv)
+  internal_function attribute_hidden;
+
+/* Compute the number of milliseconds until the specified deadline,
+   from the current time in the argument.  The result is mainly for
+   use with poll.  If the deadline has already passed, return 0.  If
+   the result would overflow an int, return INT_MAX.  */
+int __deadline_to_ms (struct deadline_current_time, struct deadline)
+  internal_function attribute_hidden;
+
+/* Return true if TV.tv_sec is non-negative and TV.tv_usec is in the
+   interval [0, 999999].  */
+static inline bool
+__is_timeval_valid_timeout (struct timeval tv)
+{
+  return tv.tv_sec >= 0 && tv.tv_usec >= 0 && tv.tv_usec < 1000 * 1000;
+}
+
 #endif /* _NET_INTERNAL_H */
diff --git a/inet/tst-deadline.c b/inet/tst-deadline.c
new file mode 100644 (file)
index 0000000..ed04345
--- /dev/null
@@ -0,0 +1,188 @@
+/* Tests for computing deadlines for timeouts.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <inet/net-internal.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <support/check.h>
+
+/* Find the maximum value which can be represented in a time_t.  */
+static time_t
+time_t_max (void)
+{
+  _Static_assert (0 > (time_t) -1, "time_t is signed");
+  uintmax_t current = 1;
+  while (true)
+    {
+      uintmax_t next = current * 2;
+      /* This cannot happen because time_t is signed.  */
+      TEST_VERIFY_EXIT (next > current);
+      ++next;
+      if ((time_t) next < 0 || next != (uintmax_t) (time_t) next)
+        /* Value cannot be represented in time_t.  Return the previous
+           value. */
+        return current;
+      current = next;
+    }
+}
+
+static int
+do_test (void)
+{
+  {
+    struct deadline_current_time current_time = __deadline_current_time ();
+    TEST_VERIFY (current_time.current.tv_sec >= 0);
+    current_time = __deadline_current_time ();
+    /* Due to CLOCK_MONOTONIC, either seconds or nanoseconds are
+       greater than zero.  This is also true for the gettimeofday
+       fallback.  */
+    TEST_VERIFY (current_time.current.tv_sec >= 0);
+    TEST_VERIFY (current_time.current.tv_sec > 0
+                 || current_time.current.tv_nsec > 0);
+  }
+
+  /* Check basic computations of deadlines.  */
+  struct deadline_current_time current_time = { { 1, 123456789 } };
+  struct deadline deadline = __deadline_from_timeval
+    (current_time, (struct timeval) { 0, 1 });
+  TEST_VERIFY (deadline.absolute.tv_sec == 1);
+  TEST_VERIFY (deadline.absolute.tv_nsec == 123457789);
+  TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 1);
+
+  deadline = __deadline_from_timeval
+    (current_time, ((struct timeval) { 0, 2 }));
+  TEST_VERIFY (deadline.absolute.tv_sec == 1);
+  TEST_VERIFY (deadline.absolute.tv_nsec == 123458789);
+  TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 1);
+
+  deadline = __deadline_from_timeval
+    (current_time, ((struct timeval) { 1, 0 }));
+  TEST_VERIFY (deadline.absolute.tv_sec == 2);
+  TEST_VERIFY (deadline.absolute.tv_nsec == 123456789);
+  TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 1000);
+
+  /* Check if timeouts are correctly rounded up to the next
+     millisecond.  */
+  for (int i = 0; i < 999999; ++i)
+    {
+      ++current_time.current.tv_nsec;
+      TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 1000);
+    }
+
+  /* A full millisecond has elapsed, so the time to the deadline is
+     now less than 1000.  */
+  ++current_time.current.tv_nsec;
+  TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 999);
+
+  /* Check __deadline_to_ms carry-over.  */
+  current_time = (struct deadline_current_time) { { 9, 123456789 } };
+  deadline = (struct deadline) { { 10, 122456789 } };
+  TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 999);
+  deadline = (struct deadline) { { 10, 122456790 } };
+  TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 1000);
+  deadline = (struct deadline) { { 10, 123456788 } };
+  TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 1000);
+  deadline = (struct deadline) { { 10, 123456789 } };
+  TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 1000);
+
+  /* Check __deadline_to_ms overflow.  */
+  deadline = (struct deadline) { { INT_MAX - 1, 1 } };
+  TEST_VERIFY (__deadline_to_ms (current_time, deadline) == INT_MAX);
+
+  /* Check __deadline_to_ms for elapsed deadlines.  */
+  current_time = (struct deadline_current_time) { { 9, 123456789 } };
+  deadline.absolute = current_time.current;
+  TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 0);
+  current_time = (struct deadline_current_time) { { 9, 123456790 } };
+  TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 0);
+  current_time = (struct deadline_current_time) { { 10, 0 } };
+  TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 0);
+  current_time = (struct deadline_current_time) { { 10, 123456788 } };
+  TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 0);
+  current_time = (struct deadline_current_time) { { 10, 123456789 } };
+  TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 0);
+
+  /* Check carry-over in __deadline_from_timeval.  */
+  current_time = (struct deadline_current_time) { { 9, 998000001 } };
+  for (int i = 0; i < 2000; ++i)
+    {
+      deadline = __deadline_from_timeval
+        (current_time, (struct timeval) { 1, i });
+      TEST_VERIFY (deadline.absolute.tv_sec == 10);
+      TEST_VERIFY (deadline.absolute.tv_nsec == 998000001 + i * 1000);
+    }
+  for (int i = 2000; i < 3000; ++i)
+    {
+      deadline = __deadline_from_timeval
+        (current_time, (struct timeval) { 2, i });
+      TEST_VERIFY (deadline.absolute.tv_sec == 12);
+      TEST_VERIFY (deadline.absolute.tv_nsec == 1 + (i - 2000) * 1000);
+    }
+
+  /* Check infinite deadlines.  */
+  deadline = __deadline_from_timeval
+    ((struct deadline_current_time) { { 0, 1000 * 1000 * 1000 - 1000 } },
+     (struct timeval) { time_t_max (), 1 });
+  TEST_VERIFY (__deadline_is_infinite (deadline));
+  deadline = __deadline_from_timeval
+    ((struct deadline_current_time) { { 0, 1000 * 1000 * 1000 - 1001 } },
+     (struct timeval) { time_t_max (), 1 });
+  TEST_VERIFY (!__deadline_is_infinite (deadline));
+  deadline = __deadline_from_timeval
+    ((struct deadline_current_time)
+       { { time_t_max (), 1000 * 1000 * 1000 - 1000 } },
+     (struct timeval) { 0, 1 });
+  TEST_VERIFY (__deadline_is_infinite (deadline));
+  deadline = __deadline_from_timeval
+    ((struct deadline_current_time)
+       { { time_t_max () / 2 + 1, 0 } },
+     (struct timeval) { time_t_max () / 2 + 1, 0 });
+  TEST_VERIFY (__deadline_is_infinite (deadline));
+
+  /* Check __deadline_first behavior.  */
+  deadline = __deadline_first
+    ((struct deadline) { { 1, 2 } },
+     (struct deadline) { { 1, 3 } });
+  TEST_VERIFY (deadline.absolute.tv_sec == 1);
+  TEST_VERIFY (deadline.absolute.tv_nsec == 2);
+  deadline = __deadline_first
+    ((struct deadline) { { 1, 3 } },
+     (struct deadline) { { 1, 2 } });
+  TEST_VERIFY (deadline.absolute.tv_sec == 1);
+  TEST_VERIFY (deadline.absolute.tv_nsec == 2);
+  deadline = __deadline_first
+    ((struct deadline) { { 1, 2 } },
+     (struct deadline) { { 2, 1 } });
+  TEST_VERIFY (deadline.absolute.tv_sec == 1);
+  TEST_VERIFY (deadline.absolute.tv_nsec == 2);
+  deadline = __deadline_first
+    ((struct deadline) { { 1, 2 } },
+     (struct deadline) { { 2, 4 } });
+  TEST_VERIFY (deadline.absolute.tv_sec == 1);
+  TEST_VERIFY (deadline.absolute.tv_nsec == 2);
+  deadline = __deadline_first
+    ((struct deadline) { { 2, 4 } },
+     (struct deadline) { { 1, 2 } });
+  TEST_VERIFY (deadline.absolute.tv_sec == 1);
+  TEST_VERIFY (deadline.absolute.tv_nsec == 2);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
index b9cff534e9b2f78c591b9e556bae51dfc3d05f92..ab1556700189b84a1c11f46b02256d0e539370ab 100644 (file)
--- 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
index 0cdb097ab61c41a459afbe77434c6031d081f7fe..127c1cfb3507a11395ad70c1022062681d93738d 100644 (file)
@@ -1,3 +1,11 @@
+2017-06-11  Santhosh Thottingal  <santhosh.thottingal@gmail.com>
+
+       [BZ #19922]
+       * locales/iso14651_t1_common: Add collation rules for U+07DA to U+07DF.
+
+       [BZ #19919]
+       * locales/iso14651_t1_common: Correct collation of U+0D36 and U+0D37.
+
 2017-01-01  Joseph Myers  <joseph@codesourcery.com>
 
        * All files with FSF copyright notices: Update copyright dates
index eef75ba65ea4132a99ddbcf603ea1a4b9dcfa3f0..0e64f26a125d63e84e59650806fa2ac59bce0a01 100644 (file)
@@ -1042,9 +1042,9 @@ collating-element <ml-bh> from "<U0D2D><U0D4D>"
 collating-element <ml-m> from "<U0D2E><U0D4D>"
 collating-element <ml-y> from "<U0D2F><U0D4D>"
 collating-element <ml-v> from "<U0D35><U0D4D>"
-collating-element <ml-s> from "<U0D38><U0D4D>"
 collating-element <ml-ss> from "<U0D36><U0D4D>"
 collating-element <ml-sh> from "<U0D37><U0D4D>"
+collating-element <ml-s> from "<U0D38><U0D4D>"
 collating-element <ml-h> from "<U0D39><U0D4D>"
 collating-element <ml-zh> from "<U0D34><U0D4D>"
 collating-element <ml-rr> from "<U0D31><U0D4D>"
@@ -1103,8 +1103,8 @@ collating-symbol <ml-rra>
 collating-symbol <ml-la>
 collating-symbol <ml-lla>
 collating-symbol <ml-va>
-collating-symbol <ml-sha>
 collating-symbol <ml-ssa>
+collating-symbol <ml-sha>
 collating-symbol <ml-sa>
 collating-symbol <ml-ha>
 collating-symbol <ml-avagrah>
@@ -1126,6 +1126,12 @@ collating-symbol <mlvs-o>
 collating-symbol <mlvs-au>
 collating-symbol <ml-visarga>
 collating-symbol <ml-virama>
+collating-symbol <ml-atomic-chillu-k>
+collating-symbol <ml-atomic-chillu-n>
+collating-symbol <ml-atomic-chillu-nn>
+collating-symbol <ml-atomic-chillu-l>
+collating-symbol <ml-atomic-chillu-ll>
+collating-symbol <ml-atomic-chillu-r>
 #
 # <BENGALI>
 #
@@ -4552,6 +4558,12 @@ collating-symbol <TIB-subA>
 <mlvs-o>
 <mlvs-au>
 <ml-visarga>
+<ml-atomic-chillu-k>
+<ml-atomic-chillu-n>
+<ml-atomic-chillu-nn>
+<ml-atomic-chillu-l>
+<ml-atomic-chillu-ll>
+<ml-atomic-chillu-r>
 #
 # <BENGALI>
 #
@@ -7252,6 +7264,7 @@ order_start <MALAYALAM>;forward;forward;forward;forward,position
 <U0D13> <mlvw-o>;<BAS>;<MIN>;IGNORE
 <U0D14> <mlvw-au>;<BAS>;<MIN>;IGNORE
 <ml-chillu-k>  "<ml-ka><ml-virama>";<BAS>;<MIN>;IGNORE
+<U0D7F>        "<ml-ka><ml-virama>";<ml-atomic-chillu-k>;<MIN>;IGNORE
 <U0D15>        "<ml-ka><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
 <ml-kh>        "<ml-kha><ml-virama>";<BAS>;<MIN>;IGNORE
 <U0D16>        "<ml-kha><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
@@ -7280,6 +7293,7 @@ order_start <MALAYALAM>;forward;forward;forward;forward,position
 <ml-dh>        "<ml-dha><ml-virama>";<BAS>;<MIN>;IGNORE
 <U0D22>        "<ml-dha><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
 <ml-chillu-nn> "<ml-nna><ml-virama>";<BAS>;<MIN>;IGNORE # ണ്‍ = ണ  + ്  + zwj
+<U0D7A>        "<ml-nna><ml-virama>";<ml-atomic-chillu-nn>;<MIN>;IGNORE
 <U0D23>        "<ml-nna><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE # ണ = ണ + ് + അ
 <ml-th>        "<ml-tha><ml-virama>";<BAS>;<MIN>;IGNORE
 <U0D24>        "<ml-tha><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
@@ -7290,6 +7304,7 @@ order_start <MALAYALAM>;forward;forward;forward;forward,position
 <ml-ddh> "<ml-ddha><ml-virama>";<BAS>;<MIN>;IGNORE
 <U0D27>        "<ml-ddha><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
 <ml-chillu-n> "<ml-na><ml-virama>";<BAS>;<MIN>;IGNORE # ന്‍= ന  + ്  + zwj
+<U0D7B>        "<ml-na><ml-virama>";<ml-atomic-chillu-n>;<MIN>;IGNORE
 <U0D28>        "<ml-na><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE  #ന = ന + ് + അ
 <ml-p> "<ml-pa><ml-virama>";<BAS>;<MIN>;IGNORE
 <U0D2A>        "<ml-pa><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
@@ -7305,20 +7320,23 @@ order_start <MALAYALAM>;forward;forward;forward;forward,position
 <ml-y>  "<ml-ya><ml-virama>";<BAS>;<MIN>;IGNORE
 <U0D2F>        "<ml-ya><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
 <ml-chillu-r> "<ml-ra><ml-virama>";<BAS>;<MIN>;IGNORE # ര = ര + ്  + zwj
+<U0D7C>        "<ml-ra><ml-virama>";<ml-atomic-chillu-r>;<MIN>;IGNORE
 <U0D30>        "<ml-ra><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE # ര = ര + ് + അ
 <ml-chillu-l> <ml-la>;<BAS>;<MIN>;IGNORE # ല്‍ = ല + ്  + zwj
+<U0D7D>        "<ml-la><ml-virama>";<ml-atomic-chillu-l>;<MIN>;IGNORE
 <U0D32>        "<ml-la><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE # ല = ല + ് + അ
 <ml-v> "<ml-va><ml-virama>";<BAS>;<MIN>;IGNORE
 <U0D35>        "<ml-va><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
 <ml-ss>        "<ml-ssa><ml-virama>";<BAS>;<MIN>;IGNORE
-<U0D37>        "<ml-ssa><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
+<U0D36>        "<ml-ssa><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
 <ml-sh>        "<ml-sha><ml-virama>";<BAS>;<MIN>;IGNORE
-<U0D36>        "<ml-sha><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
+<U0D37>        "<ml-sha><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
 <ml-s> "<ml-sa><ml-virama>";<BAS>;<MIN>;IGNORE
 <U0D38>        "<ml-sa><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
 <ml-h> "<ml-ha><ml-virama>";<BAS>;<MIN>;IGNORE
 <U0D39>        "<ml-ha><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
 <ml-chillu-ll> "<ml-lla><ml-virama>";<BAS>;<MIN>;IGNORE # ള്‍ = ള  + ്  + zwj
+<U0D7E>        "<ml-lla><ml-virama>";<ml-atomic-chillu-ll>;<MIN>;IGNORE
 <U0D33>        "<ml-lla><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE # ള = ള + ് + അ
 <ml-zh>        "<ml-zha><ml-virama>";<BAS>;<MIN>;IGNORE
 <U0D34>        "<ml-zha><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
index b91d7d6b16cd5fa4931747dc250f64636ad89222..d49e4a21c840b059647a418aca9c210fc77b758d 100644 (file)
@@ -212,9 +212,9 @@ __malloc_fork_unlock_child (void)
 #if HAVE_TUNABLES
 static inline int do_set_mallopt_check (int32_t value);
 void
-DL_TUNABLE_CALLBACK (set_mallopt_check) (void *valp)
+DL_TUNABLE_CALLBACK (set_mallopt_check) (tunable_val_t *valp)
 {
-  int32_t value = *(int32_t *) valp;
+  int32_t value = (int32_t) valp->numval;
   do_set_mallopt_check (value);
   if (check_action != 0)
     __malloc_check_init ();
@@ -223,9 +223,9 @@ DL_TUNABLE_CALLBACK (set_mallopt_check) (void *valp)
 # define DL_TUNABLE_CALLBACK_FNDECL(__name, __type) \
 static inline int do_ ## __name (__type value);                                      \
 void                                                                         \
-DL_TUNABLE_CALLBACK (__name) (void *valp)                                    \
+DL_TUNABLE_CALLBACK (__name) (tunable_val_t *valp)                           \
 {                                                                            \
-  __type value = *(__type *) valp;                                           \
+  __type value = (__type) (valp)->numval;                                    \
   do_ ## __name (value);                                                     \
 }
 
index 488579390578e09a1a232ac5161daee086dbbd6b..4e076638b00ed87cdcf81d4f356d3fb8b47b6f7d 100644 (file)
@@ -4902,7 +4902,7 @@ __libc_mallopt (int param_number, int value)
 
     case M_ARENA_MAX:
       if (value > 0)
-       do_set_arena_test (value);
+       do_set_arena_max (value);
       break;
     }
   __libc_lock_unlock (av->mutex);
index 19d76c0c37627c043a09eb1b43c05af0bb246df5..eaea7c3b893f0f14da8d6a7df2306de89499d9c1 100644 (file)
 
 #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);
 
 
index 6d48c0cfc8e672ca6ef7672f4f460d95fdadaa33..8def69ae22f90ea29d38c15efb710dbe835d13e2 100644 (file)
@@ -224,6 +224,7 @@ tests = tst-typesizes \
        tst-attr1 tst-attr2 tst-attr3 tst-default-attr \
        tst-mutex1 tst-mutex2 tst-mutex3 tst-mutex4 tst-mutex5 tst-mutex6 \
        tst-mutex7 tst-mutex8 tst-mutex9 tst-mutex5a tst-mutex7a \
+       tst-mutex7robust \
        tst-mutexpi1 tst-mutexpi2 tst-mutexpi3 tst-mutexpi4 tst-mutexpi5 \
        tst-mutexpi5a tst-mutexpi6 tst-mutexpi7 tst-mutexpi7a tst-mutexpi8 \
        tst-mutexpi9 \
@@ -241,7 +242,7 @@ tests = tst-typesizes \
        tst-rwlock4 tst-rwlock5 tst-rwlock6 tst-rwlock7 tst-rwlock8 \
        tst-rwlock9 tst-rwlock10 tst-rwlock11 tst-rwlock12 tst-rwlock13 \
        tst-rwlock14 tst-rwlock15 tst-rwlock16 tst-rwlock17 tst-rwlock18 \
-       tst-rwlock19 \
+       tst-rwlock19 tst-rwlock20 \
        tst-once1 tst-once2 tst-once3 tst-once4 tst-once5 \
        tst-key1 tst-key2 tst-key3 tst-key4 \
        tst-sem1 tst-sem2 tst-sem3 tst-sem4 tst-sem5 tst-sem6 tst-sem7 \
@@ -355,7 +356,7 @@ tests += tst-cancelx2 tst-cancelx3 tst-cancelx4 tst-cancelx5 \
         tst-oncex3 tst-oncex4
 ifeq ($(build-shared),yes)
 tests += tst-atfork2 tst-tls3 tst-tls3-malloc tst-tls4 tst-tls5 tst-_res1 \
-        tst-fini1 tst-stackguard1
+        tst-fini1 tst-stackguard1 tst-compat-forwarder
 tests-nolibpthread += tst-fini1
 ifeq ($(have-z-execstack),yes)
 tests += tst-execstack
@@ -366,7 +367,7 @@ modules-names = tst-atfork2mod tst-tls3mod tst-tls4moda tst-tls4modb \
                tst-tls5mod tst-tls5moda tst-tls5modb tst-tls5modc \
                tst-tls5modd tst-tls5mode tst-tls5modf tst-stack4mod \
                tst-_res1mod1 tst-_res1mod2 tst-execstack-mod tst-fini1mod \
-               tst-join7mod
+               tst-join7mod tst-compat-forwarder-mod
 extra-test-objs += $(addsuffix .os,$(strip $(modules-names))) \
                   tst-cleanup4aux.o tst-cleanupx4aux.o
 test-extras += $(modules-names) tst-cleanup4aux tst-cleanupx4aux
@@ -704,6 +705,8 @@ $(objpfx)tst-oddstacklimit.out: $(objpfx)tst-oddstacklimit $(objpfx)tst-basic1
        $(evaluate-test)
 endif
 
+$(objpfx)tst-compat-forwarder: $(objpfx)tst-compat-forwarder-mod.so
+
 # The tests here better do not run in parallel
 ifneq ($(filter %tests,$(MAKECMDGOALS)),)
 .NOTPARALLEL:
index 8a228ab25427e5eba37c05a012792dd40829858b..368fe3c36bfc9ee233d76eb4eef9ed95707e39b1 100644 (file)
@@ -683,8 +683,14 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
                        prot) != 0)
            goto mprot_error;
 #elif _STACK_GROWS_UP
-         if (mprotect ((char *) pd - pd->guardsize,
-                       pd->guardsize - guardsize, prot) != 0)
+         char *new_guard = (char *)(((uintptr_t) pd - guardsize)
+                                    & ~pagesize_m1);
+         char *old_guard = (char *)(((uintptr_t) pd - pd->guardsize)
+                                    & ~pagesize_m1);
+         /* The guard size difference might be > 0, but once rounded
+            to the nearest page the size difference might be zero.  */
+         if (new_guard > old_guard
+             && mprotect (old_guard, new_guard - old_guard, prot) != 0)
            goto mprot_error;
 #endif
 
index 2ef757e687fb8d12c488d3a97904f3156862212e..8f3c6b3a09fbd30d71e2b7a21ee92a1f8edd8396 100644 (file)
    symbol in libpthread, but the historical ABI requires it.  For static
    linking, there is no need to provide anything here--the libc version
    will be linked in.  For shared library ABI compatibility, there must be
-   longjmp and siglongjmp symbols in libpthread.so; so we define them using
-   IFUNC to redirect to the libc function.  */
+   longjmp and siglongjmp symbols in libpthread.so.
 
-#if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_22)
-
-# if HAVE_IFUNC
-
-#  undef INIT_ARCH
-#  define INIT_ARCH()
-#  define DEFINE_LONGJMP(name) libc_ifunc (name, &__libc_longjmp)
-
-extern __typeof(longjmp) longjmp_ifunc;
-extern __typeof(siglongjmp) siglongjmp_ifunc;
+   With an IFUNC resolver, it would be possible to avoid the indirection,
+   but the IFUNC resolver might run before the __libc_longjmp symbol has
+   been relocated, in which case the IFUNC resolver would not be able to
+   provide the correct address.  */
 
-# else  /* !HAVE_IFUNC */
+#if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_22)
 
 static void __attribute__ ((noreturn, used))
 longjmp_compat (jmp_buf env, int val)
@@ -47,14 +40,10 @@ longjmp_compat (jmp_buf env, int val)
   __libc_longjmp (env, val);
 }
 
-# define DEFINE_LONGJMP(name) strong_alias (longjmp_compat, name)
-
-# endif  /* HAVE_IFUNC */
-
-DEFINE_LONGJMP (longjmp_ifunc)
-compat_symbol (libpthread, longjmp_ifunc, longjmp, GLIBC_2_0);
+strong_alias (longjmp_compat, longjmp_alias)
+compat_symbol (libpthread, longjmp_alias, longjmp, GLIBC_2_0);
 
-strong_alias (longjmp_ifunc, siglongjmp_ifunc)
-compat_symbol (libpthread, siglongjmp_ifunc, siglongjmp, GLIBC_2_0);
+strong_alias (longjmp_alias, siglongjmp_alias)
+compat_symbol (libpthread, siglongjmp_alias, siglongjmp, GLIBC_2_0);
 
 #endif
index f8ca6ba0d94cabcc4eca61920d99fdb1f5f9a7a3..b30ddf2b3983d8a7ee0628d161b3236651362332 100644 (file)
    libpthread, but the historical ABI requires it.  For static linking,
    there is no need to provide anything here--the libc version will be
    linked in.  For shared library ABI compatibility, there must be a
-   'system' symbol in libpthread.so; so we define it using IFUNC to
-   redirect to the libc function.  */
+   'system' symbol in libpthread.so.
 
-#if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_22)
-
-# if HAVE_IFUNC
-
-extern __typeof(system) system_ifunc;
-#  undef INIT_ARCH
-#  define INIT_ARCH()
-libc_ifunc (system_ifunc, &__libc_system)
+   With an IFUNC resolver, it would be possible to avoid the indirection,
+   but the IFUNC resolver might run before the __libc_system symbol has
+   been relocated, in which case the IFUNC resolver would not be able to
+   provide the correct address.  */
 
-# else  /* !HAVE_IFUNC */
+#if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_22)
 
 static int __attribute__ ((used))
 system_compat (const char *line)
 {
   return __libc_system (line);
 }
-strong_alias (system_compat, system_ifunc)
-
-# endif  /* HAVE_IFUNC */
-
-compat_symbol (libpthread, system_ifunc, system, GLIBC_2_0);
+strong_alias (system_compat, system_alias)
+compat_symbol (libpthread, system_alias, system, GLIBC_2_0);
 
 #endif
index dc9ca4c4764be2654141493330bd8a91a989f601..4425927c300ade6c0fbbba0e486fbb3a7881c229 100644 (file)
@@ -197,11 +197,14 @@ __pthread_mutex_lock_full (pthread_mutex_t *mutex)
        {
          /* Try to acquire the lock through a CAS from 0 (not acquired) to
             our TID | assume_other_futex_waiters.  */
-         if (__glibc_likely ((oldval == 0)
-                             && (atomic_compare_and_exchange_bool_acq
-                                 (&mutex->__data.__lock,
-                                  id | assume_other_futex_waiters, 0) == 0)))
-             break;
+         if (__glibc_likely (oldval == 0))
+           {
+             oldval
+               = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
+                   id | assume_other_futex_waiters, 0);
+             if (__glibc_likely (oldval == 0))
+               break;
+           }
 
          if ((oldval & FUTEX_OWNER_DIED) != 0)
            {
index a4beb7b0dca312b627d5725e758a8d07b8232973..dd88cc4ec9dcabde50c7517146b9bca0ce57f6bd 100644 (file)
@@ -154,11 +154,14 @@ pthread_mutex_timedlock (pthread_mutex_t *mutex,
        {
          /* Try to acquire the lock through a CAS from 0 (not acquired) to
             our TID | assume_other_futex_waiters.  */
-         if (__glibc_likely ((oldval == 0)
-                             && (atomic_compare_and_exchange_bool_acq
-                                 (&mutex->__data.__lock,
-                                  id | assume_other_futex_waiters, 0) == 0)))
-             break;
+         if (__glibc_likely (oldval == 0))
+           {
+             oldval
+               = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
+                   id | assume_other_futex_waiters, 0);
+             if (__glibc_likely (oldval == 0))
+               break;
+           }
 
          if ((oldval & FUTEX_OWNER_DIED) != 0)
            {
index 256508ca2af9e48d9eeef47dcf30b8d2cfafd351..846687e1cf23df07d9687140efc2d7b6f7de435f 100644 (file)
@@ -55,7 +55,6 @@
    lock acquisition attempts, so that new incoming readers do not prolong a
    phase in which readers have acquired the lock.
 
-
    The main components of the rwlock are a writer-only lock that allows only
    one of the concurrent writers to be the primary writer, and a
    single-writer-multiple-readers lock that decides between read phases, in
    ---------------------------
    #1    0   0   0   0   Lock is idle (and in a read phase).
    #2    0   0   >0  0   Readers have acquired the lock.
-   #3    0   1   0   0   Lock is not acquired; a writer is waiting for a write
-                        phase to start or will try to start one.
+   #3    0   1   0   0   Lock is not acquired; a writer will try to start a
+                        write phase.
    #4    0   1   >0  0   Readers have acquired the lock; a writer is waiting
                         and explicit hand-over to the writer is required.
    #4a   0   1   >0  1   Same as #4 except that there are further readers
                         waiting because the writer is to be preferred.
    #5    1   0   0   0   Lock is idle (and in a write phase).
-   #6    1   0   >0  0   Write phase; readers are waiting for a read phase to
-                        start or will try to start one.
+   #6    1   0   >0  0   Write phase; readers will try to start a read phase
+                        (requires explicit hand-over to all readers that
+                        do not start the read phase).
    #7    1   1   0   0   Lock is acquired by a writer.
    #8    1   1   >0  0   Lock acquired by a writer and readers are waiting;
                         explicit hand-over to the readers is required.
@@ -375,9 +375,9 @@ __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock,
      complexity.  */
   if (__glibc_likely ((r & PTHREAD_RWLOCK_WRPHASE) == 0))
     return 0;
-
-  /* If there is no primary writer but we are in a write phase, we can try
-     to install a read phase ourself.  */
+  /* Otherwise, if we were in a write phase (states #6 or #8), we must wait
+     for explicit hand-over of the read phase; the only exception is if we
+     can start a read phase if there is no primary writer currently.  */
   while (((r & PTHREAD_RWLOCK_WRPHASE) != 0)
       && ((r & PTHREAD_RWLOCK_WRLOCKED) == 0))
     {
@@ -390,15 +390,18 @@ __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock,
        {
          /* We started the read phase, so we are also responsible for
             updating the write-phase futex.  Relaxed MO is sufficient.
-            Note that there can be no other reader that we have to wake
-            because all other readers will see the read phase started by us
-            (or they will try to start it themselves); if a writer started
-            the read phase, we cannot have started it.  Furthermore, we
-            cannot discard a PTHREAD_RWLOCK_FUTEX_USED flag because we will
-            overwrite the value set by the most recent writer (or the readers
-            before it in case of explicit hand-over) and we know that there
-            are no waiting readers.  */
-         atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 0);
+            We have to do the same steps as a writer would when handing
+            over the read phase to us because other readers cannot
+            distinguish between us and the writer; this includes
+            explicit hand-over and potentially having to wake other readers
+            (but we can pretend to do the setting and unsetting of WRLOCKED
+            atomically, and thus can skip this step).  */
+         if ((atomic_exchange_relaxed (&rwlock->__data.__wrphase_futex, 0)
+             & PTHREAD_RWLOCK_FUTEX_USED) != 0)
+           {
+             int private = __pthread_rwlock_get_private (rwlock);
+             futex_wake (&rwlock->__data.__wrphase_futex, INT_MAX, private);
+           }
          return 0;
        }
       else
@@ -407,102 +410,98 @@ __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock,
        }
     }
 
-  if ((r & PTHREAD_RWLOCK_WRPHASE) != 0)
+  /* We were in a write phase but did not install the read phase.  We cannot
+     distinguish between a writer and another reader starting the read phase,
+     so we must wait for explicit hand-over via __wrphase_futex.
+     However, __wrphase_futex might not have been set to 1 yet (either
+     because explicit hand-over to the writer is still ongoing, or because
+     the writer has started the write phase but has not yet updated
+     __wrphase_futex).  The least recent value of __wrphase_futex we can
+     read from here is the modification of the last read phase (because
+     we synchronize with the last reader in this read phase through
+     __readers; see the use of acquire MO on the fetch_add above).
+     Therefore, if we observe a value of 0 for __wrphase_futex, we need
+     to subsequently check that __readers now indicates a read phase; we
+     need to use acquire MO for this so that if we observe a read phase,
+     we will also see the modification of __wrphase_futex by the previous
+     writer.  We then need to load __wrphase_futex again and continue to
+     wait if it is not 0, so that we do not skip explicit hand-over.
+     Relaxed MO is sufficient for the load from __wrphase_futex because
+     we just use it as an indicator for when we can proceed; we use
+     __readers and the acquire MO accesses to it to eventually read from
+     the proper stores to __wrphase_futex.  */
+  unsigned int wpf;
+  bool ready = false;
+  for (;;)
     {
-      /* We are in a write phase, and there must be a primary writer because
-        of the previous loop.  Block until the primary writer gives up the
-        write phase.  This case requires explicit hand-over using
-        __wrphase_futex.
-        However, __wrphase_futex might not have been set to 1 yet (either
-        because explicit hand-over to the writer is still ongoing, or because
-        the writer has started the write phase but does not yet have updated
-        __wrphase_futex).  The least recent value of __wrphase_futex we can
-        read from here is the modification of the last read phase (because
-        we synchronize with the last reader in this read phase through
-        __readers; see the use of acquire MO on the fetch_add above).
-        Therefore, if we observe a value of 0 for __wrphase_futex, we need
-        to subsequently check that __readers now indicates a read phase; we
-        need to use acquire MO for this so that if we observe a read phase,
-        we will also see the modification of __wrphase_futex by the previous
-        writer.  We then need to load __wrphase_futex again and continue to
-        wait if it is not 0, so that we do not skip explicit hand-over.
-        Relaxed MO is sufficient for the load from __wrphase_futex because
-        we just use it as an indicator for when we can proceed; we use
-        __readers and the acquire MO accesses to it to eventually read from
-        the proper stores to __wrphase_futex.  */
-      unsigned int wpf;
-      bool ready = false;
-      for (;;)
+      while (((wpf = atomic_load_relaxed (&rwlock->__data.__wrphase_futex))
+         | PTHREAD_RWLOCK_FUTEX_USED) == (1 | PTHREAD_RWLOCK_FUTEX_USED))
        {
-         while (((wpf = atomic_load_relaxed (&rwlock->__data.__wrphase_futex))
-             | PTHREAD_RWLOCK_FUTEX_USED) == (1 | PTHREAD_RWLOCK_FUTEX_USED))
+         int private = __pthread_rwlock_get_private (rwlock);
+         if (((wpf & PTHREAD_RWLOCK_FUTEX_USED) == 0)
+             && !atomic_compare_exchange_weak_relaxed
+                 (&rwlock->__data.__wrphase_futex,
+                  &wpf, wpf | PTHREAD_RWLOCK_FUTEX_USED))
+           continue;
+         int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex,
+             1 | PTHREAD_RWLOCK_FUTEX_USED, abstime, private);
+         if (err == ETIMEDOUT)
            {
-             int private = __pthread_rwlock_get_private (rwlock);
-             if (((wpf & PTHREAD_RWLOCK_FUTEX_USED) == 0)
-                 && !atomic_compare_exchange_weak_relaxed
-                     (&rwlock->__data.__wrphase_futex,
-                      &wpf, wpf | PTHREAD_RWLOCK_FUTEX_USED))
-               continue;
-             int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex,
-                 1 | PTHREAD_RWLOCK_FUTEX_USED, abstime, private);
-             if (err == ETIMEDOUT)
+             /* If we timed out, we need to unregister.  If no read phase
+                has been installed while we waited, we can just decrement
+                the number of readers.  Otherwise, we just acquire the
+                lock, which is allowed because we give no precise timing
+                guarantees, and because the timeout is only required to
+                be in effect if we would have had to wait for other
+                threads (e.g., if futex_wait would time-out immediately
+                because the given absolute time is in the past).  */
+             r = atomic_load_relaxed (&rwlock->__data.__readers);
+             while ((r & PTHREAD_RWLOCK_WRPHASE) != 0)
                {
-                 /* If we timed out, we need to unregister.  If no read phase
-                    has been installed while we waited, we can just decrement
-                    the number of readers.  Otherwise, we just acquire the
-                    lock, which is allowed because we give no precise timing
-                    guarantees, and because the timeout is only required to
-                    be in effect if we would have had to wait for other
-                    threads (e.g., if futex_wait would time-out immediately
-                    because the given absolute time is in the past).  */
-                 r = atomic_load_relaxed (&rwlock->__data.__readers);
-                 while ((r & PTHREAD_RWLOCK_WRPHASE) != 0)
-                   {
-                     /* We don't need to make anything else visible to
-                        others besides unregistering, so relaxed MO is
-                        sufficient.  */
-                     if (atomic_compare_exchange_weak_relaxed
-                         (&rwlock->__data.__readers, &r,
-                          r - (1 << PTHREAD_RWLOCK_READER_SHIFT)))
-                       return ETIMEDOUT;
-                     /* TODO Back-off.  */
-                   }
-                 /* Use the acquire MO fence to mirror the steps taken in the
-                    non-timeout case.  Note that the read can happen both
-                    in the atomic_load above as well as in the failure case
-                    of the CAS operation.  */
-                 atomic_thread_fence_acquire ();
-                 /* We still need to wait for explicit hand-over, but we must
-                    not use futex_wait anymore because we would just time out
-                    in this case and thus make the spin-waiting we need
-                    unnecessarily expensive.  */
-                 while ((atomic_load_relaxed (&rwlock->__data.__wrphase_futex)
-                     | PTHREAD_RWLOCK_FUTEX_USED)
-                     == (1 | PTHREAD_RWLOCK_FUTEX_USED))
-                   {
-                     /* TODO Back-off?  */
-                   }
-                 ready = true;
-                 break;
+                 /* We don't need to make anything else visible to
+                    others besides unregistering, so relaxed MO is
+                    sufficient.  */
+                 if (atomic_compare_exchange_weak_relaxed
+                     (&rwlock->__data.__readers, &r,
+                      r - (1 << PTHREAD_RWLOCK_READER_SHIFT)))
+                   return ETIMEDOUT;
+                 /* TODO Back-off.  */
                }
-             /* If we got interrupted (EINTR) or the futex word does not have the
-                expected value (EAGAIN), retry.  */
+             /* Use the acquire MO fence to mirror the steps taken in the
+                non-timeout case.  Note that the read can happen both
+                in the atomic_load above as well as in the failure case
+                of the CAS operation.  */
+             atomic_thread_fence_acquire ();
+             /* We still need to wait for explicit hand-over, but we must
+                not use futex_wait anymore because we would just time out
+                in this case and thus make the spin-waiting we need
+                unnecessarily expensive.  */
+             while ((atomic_load_relaxed (&rwlock->__data.__wrphase_futex)
+                 | PTHREAD_RWLOCK_FUTEX_USED)
+                 == (1 | PTHREAD_RWLOCK_FUTEX_USED))
+               {
+                 /* TODO Back-off?  */
+               }
+             ready = true;
+             break;
            }
-         if (ready)
-           /* See below.  */
-           break;
-         /* We need acquire MO here so that we synchronize with the lock
-            release of the writer, and so that we observe a recent value of
-            __wrphase_futex (see below).  */
-         if ((atomic_load_acquire (&rwlock->__data.__readers)
-             & PTHREAD_RWLOCK_WRPHASE) == 0)
-           /* We are in a read phase now, so the least recent modification of
-              __wrphase_futex we can read from is the store by the writer
-              with value 1.  Thus, only now we can assume that if we observe
-              a value of 0, explicit hand-over is finished. Retry the loop
-              above one more time.  */
-           ready = true;
+         /* If we got interrupted (EINTR) or the futex word does not have the
+            expected value (EAGAIN), retry.  */
        }
+      if (ready)
+       /* See below.  */
+       break;
+      /* We need acquire MO here so that we synchronize with the lock
+        release of the writer, and so that we observe a recent value of
+        __wrphase_futex (see below).  */
+      if ((atomic_load_acquire (&rwlock->__data.__readers)
+         & PTHREAD_RWLOCK_WRPHASE) == 0)
+       /* We are in a read phase now, so the least recent modification of
+          __wrphase_futex we can read from is the store by the writer
+          with value 1.  Thus, only now we can assume that if we observe
+          a value of 0, explicit hand-over is finished. Retry the loop
+          above one more time.  */
+       ready = true;
     }
 
   return 0;
@@ -741,10 +740,23 @@ __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock,
          r = atomic_load_relaxed (&rwlock->__data.__readers);
        }
       /* Our snapshot of __readers is up-to-date at this point because we
-        either set WRLOCKED using a CAS or were handed over WRLOCKED from
+        either set WRLOCKED using a CAS (and update r accordingly below,
+        which was used as expected value for the CAS) or got WRLOCKED from
         another writer whose snapshot of __readers we inherit.  */
+      r |= PTHREAD_RWLOCK_WRLOCKED;
     }
 
+  /* We are the primary writer; enable blocking on __writers_futex.  Relaxed
+     MO is sufficient for futex words; acquire MO on the previous
+     modifications of __readers ensures that this store happens after the
+     store of value 0 by the previous primary writer.  */
+  atomic_store_relaxed (&rwlock->__data.__writers_futex,
+      1 | (may_share_futex_used_flag ? PTHREAD_RWLOCK_FUTEX_USED : 0));
+
+  /* If we are in a write phase, we have acquired the lock.  */
+  if ((r & PTHREAD_RWLOCK_WRPHASE) != 0)
+    goto done;
+
   /* If we are in a read phase and there are no readers, try to start a write
      phase.  */
   while (((r & PTHREAD_RWLOCK_WRPHASE) == 0)
@@ -758,166 +770,156 @@ __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock,
          &r, r | PTHREAD_RWLOCK_WRPHASE))
        {
          /* We have started a write phase, so need to enable readers to wait.
-            See the similar case in__pthread_rwlock_rdlock_full.  */
+            See the similar case in __pthread_rwlock_rdlock_full.  Unlike in
+            that similar case, we are the (only) primary writer and so do
+            not need to wake another writer.  */
          atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 1);
-         /* Make sure we fall through to the end of the function.  */
-         r |= PTHREAD_RWLOCK_WRPHASE;
-         break;
+
+         goto done;
        }
       /* TODO Back-off.  */
     }
 
-  /* We are the primary writer; enable blocking on __writers_futex.  Relaxed
-     MO is sufficient for futex words; acquire MO on the previous
-     modifications of __readers ensures that this store happens after the
-     store of value 0 by the previous primary writer.  */
-  atomic_store_relaxed (&rwlock->__data.__writers_futex,
-      1 | (may_share_futex_used_flag ? PTHREAD_RWLOCK_FUTEX_USED : 0));
-
-  if (__glibc_unlikely ((r & PTHREAD_RWLOCK_WRPHASE) == 0))
+  /* We became the primary writer in a read phase and there were readers when
+     we did (because of the previous loop).  Thus, we have to wait for
+     explicit hand-over from one of these readers.
+     We basically do the same steps as for the similar case in
+     __pthread_rwlock_rdlock_full, except that we additionally might try
+     to directly hand over to another writer and need to wake up
+     other writers or waiting readers (i.e., PTHREAD_RWLOCK_RWAITING).  */
+  unsigned int wpf;
+  bool ready = false;
+  for (;;)
     {
-      /* We are not in a read phase and there are readers (because of the
-        previous loop).  Thus, we have to wait for explicit hand-over from
-        one of these readers.
-        We basically do the same steps as for the similar case in
-        __pthread_rwlock_rdlock_full, except that we additionally might try
-        to directly hand over to another writer and need to wake up
-        other writers or waiting readers (i.e., PTHREAD_RWLOCK_RWAITING).  */
-      unsigned int wpf;
-      bool ready = false;
-      for (;;)
+      while (((wpf = atomic_load_relaxed (&rwlock->__data.__wrphase_futex))
+         | PTHREAD_RWLOCK_FUTEX_USED) == PTHREAD_RWLOCK_FUTEX_USED)
        {
-         while (((wpf = atomic_load_relaxed (&rwlock->__data.__wrphase_futex))
-             | PTHREAD_RWLOCK_FUTEX_USED) == PTHREAD_RWLOCK_FUTEX_USED)
+         int private = __pthread_rwlock_get_private (rwlock);
+         if (((wpf & PTHREAD_RWLOCK_FUTEX_USED) == 0)
+             && !atomic_compare_exchange_weak_relaxed
+                 (&rwlock->__data.__wrphase_futex, &wpf,
+                  PTHREAD_RWLOCK_FUTEX_USED))
+           continue;
+         int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex,
+             PTHREAD_RWLOCK_FUTEX_USED, abstime, private);
+         if (err == ETIMEDOUT)
            {
-             int private = __pthread_rwlock_get_private (rwlock);
-             if (((wpf & PTHREAD_RWLOCK_FUTEX_USED) == 0)
-                 && !atomic_compare_exchange_weak_relaxed
-                     (&rwlock->__data.__wrphase_futex, &wpf,
-                      PTHREAD_RWLOCK_FUTEX_USED))
-               continue;
-             int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex,
-                 PTHREAD_RWLOCK_FUTEX_USED, abstime, private);
-             if (err == ETIMEDOUT)
+             if (rwlock->__data.__flags
+                 != PTHREAD_RWLOCK_PREFER_READER_NP)
                {
-                 if (rwlock->__data.__flags
-                     != PTHREAD_RWLOCK_PREFER_READER_NP)
-                   {
-                     /* We try writer--writer hand-over.  */
-                     unsigned int w = atomic_load_relaxed
-                         (&rwlock->__data.__writers);
-                     if (w != 0)
-                       {
-                         /* We are about to hand over WRLOCKED, so we must
-                            release __writers_futex too; otherwise, we'd have
-                            a pending store, which could at least prevent
-                            other threads from waiting using the futex
-                            because it could interleave with the stores
-                            by subsequent writers.  In turn, this means that
-                            we have to clean up when we do not hand over
-                            WRLOCKED.
-                            Release MO so that another writer that gets
-                            WRLOCKED from us can take over our view of
-                            __readers.  */
-                         unsigned int wf = atomic_exchange_relaxed
-                             (&rwlock->__data.__writers_futex, 0);
-                         while (w != 0)
-                           {
-                             if (atomic_compare_exchange_weak_release
-                                 (&rwlock->__data.__writers, &w,
-                                     w | PTHREAD_RWLOCK_WRHANDOVER))
-                               {
-                                 /* Wake other writers.  */
-                                 if ((wf & PTHREAD_RWLOCK_FUTEX_USED) != 0)
-                                   futex_wake
-                                       (&rwlock->__data.__writers_futex, 1,
-                                        private);
-                                 return ETIMEDOUT;
-                               }
-                             /* TODO Back-off.  */
-                           }
-                         /* We still own WRLOCKED and someone else might set
-                            a write phase concurrently, so enable waiting
-                            again.  Make sure we don't loose the flag that
-                            signals whether there are threads waiting on
-                            this futex.  */
-                         atomic_store_relaxed
-                             (&rwlock->__data.__writers_futex, wf);
-                       }
-                   }
-                 /* If we timed out and we are not in a write phase, we can
-                    just stop being a primary writer.  Otherwise, we just
-                    acquire the lock.  */
-                 r = atomic_load_relaxed (&rwlock->__data.__readers);
-                 if ((r & PTHREAD_RWLOCK_WRPHASE) == 0)
+                 /* We try writer--writer hand-over.  */
+                 unsigned int w = atomic_load_relaxed
+                     (&rwlock->__data.__writers);
+                 if (w != 0)
                    {
-                     /* We are about to release WRLOCKED, so we must release
-                        __writers_futex too; see the handling of
-                        writer--writer hand-over above.  */
+                     /* We are about to hand over WRLOCKED, so we must
+                        release __writers_futex too; otherwise, we'd have
+                        a pending store, which could at least prevent
+                        other threads from waiting using the futex
+                        because it could interleave with the stores
+                        by subsequent writers.  In turn, this means that
+                        we have to clean up when we do not hand over
+                        WRLOCKED.
+                        Release MO so that another writer that gets
+                        WRLOCKED from us can take over our view of
+                        __readers.  */
                      unsigned int wf = atomic_exchange_relaxed
                          (&rwlock->__data.__writers_futex, 0);
-                     while ((r & PTHREAD_RWLOCK_WRPHASE) == 0)
+                     while (w != 0)
                        {
-                         /* While we don't need to make anything from a
-                            caller's critical section visible to other
-                            threads, we need to ensure that our changes to
-                            __writers_futex are properly ordered.
-                            Therefore, use release MO to synchronize with
-                            subsequent primary writers.  Also wake up any
-                            waiting readers as they are waiting because of
-                            us.  */
                          if (atomic_compare_exchange_weak_release
-                             (&rwlock->__data.__readers, &r,
-                              (r ^ PTHREAD_RWLOCK_WRLOCKED)
-                              & ~(unsigned int) PTHREAD_RWLOCK_RWAITING))
+                             (&rwlock->__data.__writers, &w,
+                                 w | PTHREAD_RWLOCK_WRHANDOVER))
                            {
                              /* Wake other writers.  */
                              if ((wf & PTHREAD_RWLOCK_FUTEX_USED) != 0)
                                futex_wake (&rwlock->__data.__writers_futex,
-                                   1, private);
-                             /* Wake waiting readers.  */
-                             if ((r & PTHREAD_RWLOCK_RWAITING) != 0)
-                               futex_wake (&rwlock->__data.__readers,
-                                   INT_MAX, private);
+                                           1, private);
                              return ETIMEDOUT;
                            }
+                         /* TODO Back-off.  */
                        }
-                     /* We still own WRLOCKED and someone else might set a
-                        write phase concurrently, so enable waiting again.
-                        Make sure we don't loose the flag that signals
-                        whether there are threads waiting on this futex.  */
-                     atomic_store_relaxed (&rwlock->__data.__writers_futex,
-                         wf);
+                     /* We still own WRLOCKED and someone else might set
+                        a write phase concurrently, so enable waiting
+                        again.  Make sure we don't loose the flag that
+                        signals whether there are threads waiting on
+                        this futex.  */
+                     atomic_store_relaxed
+                         (&rwlock->__data.__writers_futex, wf);
                    }
-                 /* Use the acquire MO fence to mirror the steps taken in the
-                    non-timeout case.  Note that the read can happen both
-                    in the atomic_load above as well as in the failure case
-                    of the CAS operation.  */
-                 atomic_thread_fence_acquire ();
-                 /* We still need to wait for explicit hand-over, but we must
-                    not use futex_wait anymore.  */
-                 while ((atomic_load_relaxed
-                     (&rwlock->__data.__wrphase_futex)
-                      | PTHREAD_RWLOCK_FUTEX_USED)
-                     == PTHREAD_RWLOCK_FUTEX_USED)
+               }
+             /* If we timed out and we are not in a write phase, we can
+                just stop being a primary writer.  Otherwise, we just
+                acquire the lock.  */
+             r = atomic_load_relaxed (&rwlock->__data.__readers);
+             if ((r & PTHREAD_RWLOCK_WRPHASE) == 0)
+               {
+                 /* We are about to release WRLOCKED, so we must release
+                    __writers_futex too; see the handling of
+                    writer--writer hand-over above.  */
+                 unsigned int wf = atomic_exchange_relaxed
+                     (&rwlock->__data.__writers_futex, 0);
+                 while ((r & PTHREAD_RWLOCK_WRPHASE) == 0)
                    {
-                     /* TODO Back-off.  */
+                     /* While we don't need to make anything from a
+                        caller's critical section visible to other
+                        threads, we need to ensure that our changes to
+                        __writers_futex are properly ordered.
+                        Therefore, use release MO to synchronize with
+                        subsequent primary writers.  Also wake up any
+                        waiting readers as they are waiting because of
+                        us.  */
+                     if (atomic_compare_exchange_weak_release
+                         (&rwlock->__data.__readers, &r,
+                          (r ^ PTHREAD_RWLOCK_WRLOCKED)
+                          & ~(unsigned int) PTHREAD_RWLOCK_RWAITING))
+                       {
+                         /* Wake other writers.  */
+                         if ((wf & PTHREAD_RWLOCK_FUTEX_USED) != 0)
+                           futex_wake (&rwlock->__data.__writers_futex,
+                               1, private);
+                         /* Wake waiting readers.  */
+                         if ((r & PTHREAD_RWLOCK_RWAITING) != 0)
+                           futex_wake (&rwlock->__data.__readers,
+                               INT_MAX, private);
+                         return ETIMEDOUT;
+                       }
                    }
-                 ready = true;
-                 break;
+                 /* We still own WRLOCKED and someone else might set a
+                    write phase concurrently, so enable waiting again.
+                    Make sure we don't loose the flag that signals
+                    whether there are threads waiting on this futex.  */
+                 atomic_store_relaxed (&rwlock->__data.__writers_futex, wf);
                }
-             /* If we got interrupted (EINTR) or the futex word does not have
-                the expected value (EAGAIN), retry.  */
+             /* Use the acquire MO fence to mirror the steps taken in the
+                non-timeout case.  Note that the read can happen both
+                in the atomic_load above as well as in the failure case
+                of the CAS operation.  */
+             atomic_thread_fence_acquire ();
+             /* We still need to wait for explicit hand-over, but we must
+                not use futex_wait anymore.  */
+             while ((atomic_load_relaxed
+                 (&rwlock->__data.__wrphase_futex)
+                  | PTHREAD_RWLOCK_FUTEX_USED)
+                 == PTHREAD_RWLOCK_FUTEX_USED)
+               {
+                 /* TODO Back-off.  */
+               }
+             ready = true;
+             break;
            }
-         /* See pthread_rwlock_rdlock_full.  */
-         if (ready)
-           break;
-         if ((atomic_load_acquire (&rwlock->__data.__readers)
-             & PTHREAD_RWLOCK_WRPHASE) != 0)
-           ready = true;
+         /* If we got interrupted (EINTR) or the futex word does not have
+            the expected value (EAGAIN), retry.  */
        }
+      /* See pthread_rwlock_rdlock_full.  */
+      if (ready)
+       break;
+      if ((atomic_load_acquire (&rwlock->__data.__readers)
+         & PTHREAD_RWLOCK_WRPHASE) != 0)
+       ready = true;
     }
 
+ done:
   atomic_store_relaxed (&rwlock->__data.__cur_writer,
       THREAD_GETMEM (THREAD_SELF, tid));
   return 0;
diff --git a/nptl/tst-compat-forwarder-mod.c b/nptl/tst-compat-forwarder-mod.c
new file mode 100644 (file)
index 0000000..823bfa2
--- /dev/null
@@ -0,0 +1,28 @@
+/* Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* Call the function system through a statically initialized pointer.  */
+
+#include <stdlib.h>
+
+int (*system_function) (const char *) = system;
+
+void
+call_system (void)
+{
+  system_function (NULL);
+}
diff --git a/nptl/tst-compat-forwarder.c b/nptl/tst-compat-forwarder.c
new file mode 100644 (file)
index 0000000..f96806b
--- /dev/null
@@ -0,0 +1,35 @@
+/* Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* Test that the compat forwaders in libpthread work correctly.  */
+
+#include <support/test-driver.h>
+
+extern void call_system (void);
+
+int
+do_test (void)
+{
+  /* Calling the system function from a shared library that is not linked
+     against libpthread, when the main program is linked against
+     libpthread, should not crash.  */
+  call_system ();
+
+  return 0;
+}
+
+#include <support/test-driver.c>
index a11afdba5e0ef27ddcb447006f4b623e5765d0e0..08fe251eebba8c7e0ca4b2b95bbe0804f8d69a4a 100644 (file)
 #include <stdlib.h>
 #include <time.h>
 
-
+/* This test is a template for other tests to use.  Other tests define
+   the following macros to change the behaviour of the template test.
+   The test is very simple, it configures N threads given the parameters
+   below and then proceeds to go through mutex lock and unlock
+   operations in each thread as described before for the thread
+   function.  */
 #ifndef TYPE
 # define TYPE PTHREAD_MUTEX_DEFAULT
 #endif
-
+#ifndef ROBUST
+# define ROBUST PTHREAD_MUTEX_STALLED
+#endif
+#ifndef DELAY_NSEC
+# define DELAY_NSEC 11000
+#endif
+#ifndef ROUNDS
+# define ROUNDS 1000
+#endif
+#ifndef N
+# define N 100
+#endif
 
 static pthread_mutex_t lock;
 
-
-#define ROUNDS 1000
-#define N 100
-
-
+/* Each thread locks and the subsequently unlocks the lock, yielding
+   the smallest critical section possible.  After the unlock the thread
+   waits DELAY_NSEC nanoseconds before doing the lock and unlock again.
+   Every thread does this ROUNDS times.  The lock and unlock are
+   checked for errors.  */
 static void *
 tf (void *arg)
 {
   int nr = (long int) arg;
   int cnt;
-  struct timespec ts = { .tv_sec = 0, .tv_nsec = 11000 };
+  struct timespec ts = { .tv_sec = 0, .tv_nsec = DELAY_NSEC };
 
   for (cnt = 0; cnt < ROUNDS; ++cnt)
     {
@@ -56,13 +72,16 @@ tf (void *arg)
          return (void *) 1l;
        }
 
-      nanosleep (&ts, NULL);
+      if ((ts.tv_sec > 0) || (ts.tv_nsec > 0))
+       nanosleep (&ts, NULL);
     }
 
   return NULL;
 }
 
-
+/* Setup and run N threads, where each thread does as described
+   in the above thread function.  The threads are given a minimal 1MiB
+   stack since they don't do anything between the lock and unlock.  */
 static int
 do_test (void)
 {
@@ -80,6 +99,12 @@ do_test (void)
       exit (1);
     }
 
+  if (pthread_mutexattr_setrobust (&a, ROBUST) != 0)
+    {
+      puts ("mutexattr_setrobust failed");
+      exit (1);
+    }
+
 #ifdef ENABLE_PI
   if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT) != 0)
     {
diff --git a/nptl/tst-mutex7robust.c b/nptl/tst-mutex7robust.c
new file mode 100644 (file)
index 0000000..8221a61
--- /dev/null
@@ -0,0 +1,7 @@
+/* Bug 21778: Fix oversight in robust mutex lock acquisition.  */
+#define TYPE PTHREAD_MUTEX_NORMAL
+#define ROBUST PTHREAD_MUTEX_ROBUST
+#define DELAY_NSEC 0
+#define ROUNDS 1000
+#define N 32
+#include "tst-mutex7.c"
diff --git a/nptl/tst-rwlock20.c b/nptl/tst-rwlock20.c
new file mode 100644 (file)
index 0000000..4aeea2b
--- /dev/null
@@ -0,0 +1,116 @@
+/* Test program for a read-phase / write-phase explicit hand-over.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <error.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <time.h>
+#include <atomic.h>
+#include <support/xthread.h>
+
+/* We realy want to set threads to 2 to reproduce this issue. The goal
+   is to have one primary writer and a single reader, and to hit the
+   bug that happens in the interleaving of those two phase transitions.
+   However, on most hardware, adding a second writer seems to help the
+   interleaving happen slightly more often, say 20% of the time.  On a
+   16 core ppc64 machine this fails 100% of the time with an unpatched
+   glibc.  On a 8 core x86_64 machine this fails ~93% of the time, but
+   it doesn't fail at all on a 4 core system, so having available
+   unloaded cores makes a big difference in reproducibility.  On an 8
+   core qemu/kvm guest the reproducer reliability drops to ~10%.  */
+#define THREADS 3
+
+#define KIND PTHREAD_RWLOCK_PREFER_READER_NP
+
+static pthread_rwlock_t lock;
+static int done = 0;
+
+static void*
+tf (void* arg)
+{
+  while (atomic_load_relaxed (&done) == 0)
+    {
+      int rcnt = 0;
+      int wcnt = 100;
+      if ((uintptr_t) arg == 0)
+       {
+         rcnt = 1;
+         wcnt = 1;
+       }
+
+      do
+       {
+         if (wcnt)
+           {
+             xpthread_rwlock_wrlock (&lock);
+             xpthread_rwlock_unlock (&lock);
+             wcnt--;
+         }
+         if (rcnt)
+           {
+             xpthread_rwlock_rdlock (&lock);
+             xpthread_rwlock_unlock (&lock);
+             rcnt--;
+         }
+       }
+      while ((atomic_load_relaxed (&done) == 0) && (rcnt + wcnt > 0));
+
+    }
+    return NULL;
+}
+
+
+
+static int
+do_test (void)
+{
+  pthread_t thr[THREADS];
+  int n;
+  pthread_rwlockattr_t attr;
+
+  xpthread_rwlockattr_init (&attr);
+  xpthread_rwlockattr_setkind_np (&attr, KIND);
+
+  xpthread_rwlock_init (&lock, &attr);
+
+  /* Make standard error the same as standard output.  */
+  dup2 (1, 2);
+
+  /* Make sure we see all message, even those on stdout.  */
+  setvbuf (stdout, NULL, _IONBF, 0);
+
+  for (n = 0; n < THREADS; ++n)
+    thr[n] = xpthread_create (NULL, tf, (void *) (uintptr_t) n);
+
+  struct timespec delay;
+  delay.tv_sec = 10;
+  delay.tv_nsec = 0;
+  nanosleep (&delay, NULL);
+  atomic_store_relaxed (&done, 1);
+
+  /* Wait for all the threads.  */
+  for (n = 0; n < THREADS; ++n)
+    xpthread_join (thr[n]);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
index 8f23d647c80bc2a67f3980e4bb155cbe8acc8c33..ccbfcf3c48b1a4b1b0966a237ed20ee56d2a5633 100644 (file)
@@ -43,7 +43,7 @@ routines :=                                                                 \
        getpgid setpgid getpgrp bsd-getpgrp setpgrp getsid setsid             \
        getresuid getresgid setresuid setresgid                               \
        pathconf sysconf fpathconf                                            \
-       glob glob64 fnmatch regex                                             \
+       glob glob64 globfree globfree64 glob_pattern_p fnmatch regex          \
        confstr                                                               \
        getopt getopt1 getopt_init                                            \
        sched_setp sched_getp sched_sets sched_gets sched_yield sched_primax  \
@@ -91,7 +91,8 @@ tests         := tstgetopt testfnm runtests runptests      \
                   tst-pathconf tst-getaddrinfo4 tst-rxspencer-no-utf8 \
                   tst-fnmatch3 bug-regex36 tst-getaddrinfo5 \
                   tst-posix_spawn-fd \
-                  tst-posix_fadvise tst-posix_fadvise64
+                  tst-posix_fadvise tst-posix_fadvise64 \
+                  tst-glob-tilde
 xtests         := bug-ga2
 ifeq (yes,$(build-shared))
 test-srcs      := globtest
@@ -134,7 +135,8 @@ tests-special += $(objpfx)bug-regex2-mem.out $(objpfx)bug-regex14-mem.out \
                 $(objpfx)tst-rxspencer-no-utf8-mem.out $(objpfx)tst-pcre-mem.out \
                 $(objpfx)tst-boost-mem.out $(objpfx)tst-getconf.out \
                 $(objpfx)bug-glob2-mem.out $(objpfx)tst-vfork3-mem.out \
-                $(objpfx)tst-fnmatch-mem.out $(objpfx)bug-regex36-mem.out
+                $(objpfx)tst-fnmatch-mem.out $(objpfx)bug-regex36-mem.out \
+                $(objpfx)tst-glob-tilde-mem.out
 xtests-special += $(objpfx)bug-ga2-mem.out
 endif
 
@@ -341,6 +343,12 @@ $(objpfx)bug-glob2-mem.out: $(objpfx)bug-glob2.out
        $(common-objpfx)malloc/mtrace $(objpfx)bug-glob2.mtrace > $@; \
        $(evaluate-test)
 
+tst-glob-tilde-ENV = MALLOC_TRACE=$(objpfx)tst-glob-tilde.mtrace
+
+$(objpfx)tst-glob-tilde-mem.out: $(objpfx)tst-glob-tilde.out
+       $(common-objpfx)malloc/mtrace $(objpfx)tst-glob-tilde.mtrace > $@; \
+       $(evaluate-test)
+
 $(inst_libexecdir)/getconf: $(inst_bindir)/getconf \
                            $(objpfx)getconf.speclist FORCE
        $(addprefix $(..)./scripts/mkinstalldirs ,\
diff --git a/posix/flexmember.h b/posix/flexmember.h
new file mode 100644 (file)
index 0000000..107c1f0
--- /dev/null
@@ -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
+   <http://www.gnu.org/licenses/>.
+
+   Written by Paul Eggert.  */
+
+#include <stddef.h>
+
+/* 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))
index c6538091180fda5d30216efac35c365da9a27241..b2273ea7bce40552f3d45d74214868dec8cf232d 100644 (file)
@@ -15,7 +15,7 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#ifdef HAVE_CONFIG_H
+#ifndef _LIBC
 # include <config.h>
 #endif
 
 #include <stdbool.h>
 #include <stddef.h>
 #include <stdint.h>
-
-/* Outcomment the following line for production quality code.  */
-/* #define NDEBUG 1 */
 #include <assert.h>
+#include <unistd.h>
 
-#include <stdio.h>             /* Needed on stupid SunOS for assert.  */
-
-#if !defined _LIBC || !defined GLOB_ONLY_P
-#if defined HAVE_UNISTD_H || defined _LIBC
-# include <unistd.h>
-# ifndef POSIX
-#  ifdef _POSIX_VERSION
-#   define POSIX
-#  endif
-# endif
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+# define WINDOWS32
 #endif
 
-#include <pwd.h>
-
-#if defined HAVE_STDINT_H || defined _LIBC
-# include <stdint.h>
-#elif !defined UINTPTR_MAX
-# define UINTPTR_MAX (~((size_t) 0))
+#ifndef WINDOWS32
+# include <pwd.h>
 #endif
 
 #include <errno.h>
 # define __set_errno(val) errno = (val)
 #endif
 
-#if defined HAVE_DIRENT_H || defined __GNU_LIBRARY__
-# include <dirent.h>
-#else
-# define dirent direct
-# ifdef HAVE_SYS_NDIR_H
-#  include <sys/ndir.h>
-# endif
-# ifdef HAVE_SYS_DIR_H
-#  include <sys/dir.h>
-# endif
-# ifdef HAVE_NDIR_H
-#  include <ndir.h>
-# endif
-# ifdef HAVE_VMSDIR_H
-#  include "vmsdir.h"
-# endif /* HAVE_VMSDIR_H */
-#endif
-
+#include <dirent.h>
 #include <stdlib.h>
 #include <string.h>
 #include <alloca.h>
 # 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 <fnmatch.h>
 
+#include <flexmember.h>
+#include <glob_internal.h>
+
 #ifdef _SC_GETPW_R_SIZE_MAX
 # define GETPW_R_SIZE_MAX()    sysconf (_SC_GETPW_R_SIZE_MAX)
 #else
 \f
 static const char *next_brace_sub (const char *begin, int flags) __THROWNL;
 
+typedef uint_fast8_t dirent_type;
+
+#if !defined _LIBC && !defined HAVE_STRUCT_DIRENT_D_TYPE
+/* Any distinct values will do here.
+   Undef any existing macros out of the way.  */
+# undef DT_UNKNOWN
+# undef DT_DIR
+# undef DT_LNK
+# define DT_UNKNOWN 0
+# define DT_DIR 1
+# define DT_LNK 2
+#endif
+
 /* A representation of a directory entry which does not depend on the
    layout of struct dirent, or the size of ino_t.  */
 struct readdir_result
 {
   const char *name;
-# if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE
-  uint8_t type;
-# endif
+#if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE
+  dirent_type type;
+#endif
+#if defined _LIBC || defined D_INO_IN_DIRENT
   bool skip_entry;
+#endif
 };
 
-# if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE
-/* Initializer based on the d_type member of struct dirent.  */
-#  define D_TYPE_TO_RESULT(source) (source)->d_type,
-
-/* True if the directory entry D might be a symbolic link.  */
-static bool
-readdir_result_might_be_symlink (struct readdir_result d)
-{
-  return d.type == DT_UNKNOWN || d.type == DT_LNK;
-}
-
-/* True if the directory entry D might be a directory.  */
-static bool
-readdir_result_might_be_dir (struct readdir_result d)
-{
-  return d.type == DT_DIR || readdir_result_might_be_symlink (d);
-}
-# else /* defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE */
-#  define D_TYPE_TO_RESULT(source)
-
-/* If we do not have type information, symbolic links and directories
-   are always a possibility.  */
-
-static bool
-readdir_result_might_be_symlink (struct readdir_result d)
+/* Initialize and return type member of struct readdir_result.  */
+static dirent_type
+readdir_result_type (struct readdir_result d)
 {
-  return true;
+#if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE
+# define D_TYPE_TO_RESULT(source) (source)->d_type,
+  return d.type;
+#else
+# define D_TYPE_TO_RESULT(source)
+  return DT_UNKNOWN;
+#endif
 }
 
+/* Initialize and return skip_entry member of struct readdir_result.  */
 static bool
-readdir_result_might_be_dir (struct readdir_result d)
+readdir_result_skip_entry (struct readdir_result d)
 {
-  return true;
-}
-
-# endif /* defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE */
-
-# if (defined POSIX || defined WINDOWS32) && !defined __GNU_LIBRARY__
 /* Initializer for skip_entry.  POSIX does not require that the d_ino
    field be present, and some systems do not provide it. */
-#  define D_INO_TO_RESULT(source) false,
-# else
-#  define D_INO_TO_RESULT(source) (source)->d_ino == 0,
-# endif
+#if defined _LIBC || defined D_INO_IN_DIRENT
+# define D_INO_TO_RESULT(source) (source)->d_ino == 0,
+  return d.skip_entry;
+#else
+# define D_INO_TO_RESULT(source)
+  return false;
+#endif
+}
 
 /* Construct an initializer for a struct readdir_result object from a
    struct dirent *.  No copy of the name is made.  */
@@ -186,8 +155,6 @@ readdir_result_might_be_dir (struct readdir_result d)
     D_INO_TO_RESULT (source)              \
   }
 
-#endif /* !defined _LIBC || !defined GLOB_ONLY_P */
-
 /* Call gl_readdir on STREAM.  This macro can be overridden to reduce
    type safety if an old interface version needs to be supported.  */
 #ifndef GL_READDIR
@@ -225,18 +192,55 @@ convert_dirent64 (const struct dirent64 *source)
 }
 #endif
 
+#ifndef _LIBC
+/* The results of opendir() in this file are not used with dirfd and fchdir,
+   and we do not leak fds to any single-threaded code that could use stdio,
+   therefore save some unnecessary recursion in fchdir.c and opendir_safer.c.
+   FIXME - if the kernel ever adds support for multi-thread safety for
+   avoiding standard fds, then we should use opendir_safer.  */
+# ifdef GNULIB_defined_opendir
+#  undef opendir
+# endif
+# ifdef GNULIB_defined_closedir
+#  undef closedir
+# endif
 
-#ifndef attribute_hidden
-# define attribute_hidden
+/* Just use malloc.  */
+# define __libc_use_alloca(n) false
+# define alloca_account(len, avar) ((void) (len), (void) (avar), (void *) 0)
+# define extend_alloca_account(buf, len, newlen, avar) \
+    ((void) (buf), (void) (len), (void) (newlen), (void) (avar), (void *) 0)
 #endif
 
+/* Set *R = A + B.  Return true if the answer is mathematically
+   incorrect due to overflow; in this case, *R is the low order
+   bits of the correct answer.  */
+
+static bool
+size_add_wrapv (size_t a, size_t b, size_t *r)
+{
+#if 5 <= __GNUC__ && !defined __ICC
+  return __builtin_add_overflow (a, b, r);
+#else
+  *r = a + b;
+  return *r < a;
+#endif
+}
+
+static bool
+glob_use_alloca (size_t alloca_used, size_t len)
+{
+  size_t size;
+  return (!size_add_wrapv (alloca_used, len, &size)
+          && __libc_use_alloca (size));
+}
+
 static int glob_in_dir (const char *pattern, const char *directory,
                        int flags, int (*errfunc) (const char *, int),
                        glob_t *pglob, size_t alloca_used);
 extern int __glob_pattern_type (const char *pattern, int quote)
     attribute_hidden;
 
-#if !defined _LIBC || !defined GLOB_ONLY_P
 static int prefix_array (const char *prefix, char **array, size_t n) __THROWNL;
 static int collated_compare (const void *, const void *) __THROWNL;
 
@@ -265,16 +269,15 @@ next_brace_sub (const char *cp, int flags)
   return *cp != '\0' ? cp : NULL;
 }
 
-#endif /* !defined _LIBC || !defined GLOB_ONLY_P */
 
 /* Do glob searching for PATTERN, placing results in PGLOB.
    The bits defined above may be set in FLAGS.
    If a directory cannot be opened or read and ERRFUNC is not nil,
    it is called with the pathname that caused the error, and the
-   `errno' value from the failing call; if it returns non-zero
-   `glob' returns GLOB_ABORTED; if it returns zero, the error is ignored.
+   'errno' value from the failing call; if it returns non-zero
+   'glob' returns GLOB_ABORTED; if it returns zero, the error is ignored.
    If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned.
-   Otherwise, `glob' returns zero.  */
+   Otherwise, 'glob' returns zero.  */
 int
 #ifdef GLOB_ATTRIBUTE
 GLOB_ATTRIBUTE
@@ -292,9 +295,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
   int malloc_dirname = 0;
   glob_t dirs;
   int retval = 0;
-#ifdef _LIBC
   size_t alloca_used = 0;
-#endif
 
   if (pattern == NULL || pglob == NULL || (flags & ~__GLOB_FLAGS) != 0)
     {
@@ -308,7 +309,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
     flags |= GLOB_ONLYDIR;
 
   if (!(flags & GLOB_DOOFFS))
-    /* Have to do this so `globfree' knows where to start freeing.  It
+    /* Have to do this so 'globfree' knows where to start freeing.  It
        also makes all the code that uses gl_offs simpler. */
     pglob->gl_offs = 0;
 
@@ -372,14 +373,12 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
          size_t rest_len;
          char *onealt;
          size_t pattern_len = strlen (pattern) - 1;
-#ifdef _LIBC
-         int alloca_onealt = __libc_use_alloca (alloca_used + pattern_len);
+         int alloca_onealt = glob_use_alloca (alloca_used, pattern_len);
          if (alloca_onealt)
            onealt = alloca_account (pattern_len, alloca_used);
          else
-#endif
            {
-             onealt = (char *) malloc (pattern_len);
+             onealt = malloc (pattern_len);
              if (onealt == NULL)
                return GLOB_NOSPACE;
            }
@@ -392,11 +391,9 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
          next = next_brace_sub (begin + 1, flags);
          if (next == NULL)
            {
-             /* It is an illegal expression.  */
+             /* It is an invalid expression.  */
            illegal_brace:
-#ifdef _LIBC
              if (__glibc_unlikely (!alloca_onealt))
-#endif
                free (onealt);
              flags &= ~GLOB_BRACE;
              goto no_brace;
@@ -437,9 +434,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
              /* If we got an error, return it.  */
              if (result && result != GLOB_NOMATCH)
                {
-#ifdef _LIBC
                  if (__glibc_unlikely (!alloca_onealt))
-#endif
                    free (onealt);
                  if (!(flags & GLOB_APPEND))
                    {
@@ -458,9 +453,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
              assert (next != NULL);
            }
 
-#ifdef _LIBC
          if (__glibc_unlikely (!alloca_onealt))
-#endif
            free (onealt);
 
          if (pglob->gl_pathc != firstc)
@@ -476,14 +469,16 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
 
   /* Find the filename.  */
   filename = strrchr (pattern, '/');
+
 #if defined __MSDOS__ || defined WINDOWS32
-  /* The case of "d:pattern".  Since `:' is not allowed in
+  /* The case of "d:pattern".  Since ':' is not allowed in
      file names, we can safely assume that wherever it
      happens in pattern, it signals the filename part.  This
      is so we could some day support patterns like "[a-z]:foo".  */
   if (filename == NULL)
     filename = strchr (pattern, ':');
 #endif /* __MSDOS__ || WINDOWS32 */
+
   dirname_modified = 0;
   if (filename == NULL)
     {
@@ -508,11 +503,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
            }
 
          filename = pattern;
-#ifdef _AMIGA
-         dirname = (char *) "";
-#else
          dirname = (char *) ".";
-#endif
          dirlen = 0;
        }
     }
@@ -536,22 +527,21 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
          char *drive_spec;
 
          ++dirlen;
-         drive_spec = (char *) __alloca (dirlen + 1);
+         drive_spec = __alloca (dirlen + 1);
          *((char *) mempcpy (drive_spec, pattern, dirlen)) = '\0';
          /* For now, disallow wildcards in the drive spec, to
             prevent infinite recursion in glob.  */
          if (__glob_pattern_p (drive_spec, !(flags & GLOB_NOESCAPE)))
            return GLOB_NOMATCH;
-         /* If this is "d:pattern", we need to copy `:' to DIRNAME
+         /* If this is "d:pattern", we need to copy ':' to DIRNAME
             as well.  If it's "d:/pattern", don't remove the slash
             from "d:/", since "d:" and "d:/" are not the same.*/
        }
 #endif
-#ifdef _LIBC
-      if (__libc_use_alloca (alloca_used + dirlen + 1))
+
+      if (glob_use_alloca (alloca_used, dirlen + 1))
        newp = alloca_account (dirlen + 1, alloca_used);
       else
-#endif
        {
          newp = malloc (dirlen + 1);
          if (newp == NULL)
@@ -562,14 +552,17 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
       dirname = newp;
       ++filename;
 
-      if (filename[0] == '\0'
 #if defined __MSDOS__ || defined WINDOWS32
-         && dirname[dirlen - 1] != ':'
-         && (dirlen < 3 || dirname[dirlen - 2] != ':'
-             || dirname[dirlen - 1] != '/')
+      bool drive_root = (dirlen > 1
+                         && (dirname[dirlen - 1] == ':'
+                             || (dirlen > 2 && dirname[dirlen - 2] == ':'
+                                 && dirname[dirlen - 1] == '/')));
+#else
+      bool drive_root = false;
 #endif
-         && dirlen > 1)
-       /* "pattern/".  Expand "pattern", appending slashes.  */
+
+      if (filename[0] == '\0' && dirlen > 1 && !drive_root)
+        /* "pattern/".  Expand "pattern", appending slashes.  */
        {
          int orig_flags = flags;
          if (!(flags & GLOB_NOESCAPE) && dirname[dirlen - 1] == '\\')
@@ -602,7 +595,6 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
        }
     }
 
-#ifndef VMS
   if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && dirname[0] == '~')
     {
       if (dirname[1] == '\0' || dirname[1] == '/'
@@ -612,100 +604,127 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
          /* Look up home directory.  */
          char *home_dir = getenv ("HOME");
          int malloc_home_dir = 0;
-# ifdef _AMIGA
-         if (home_dir == NULL || home_dir[0] == '\0')
-           home_dir = "SYS:";
-# else
-#  ifdef WINDOWS32
-         if (home_dir == NULL || home_dir[0] == '\0')
-           home_dir = "c:/users/default"; /* poor default */
-#  else
          if (home_dir == NULL || home_dir[0] == '\0')
            {
+#ifdef WINDOWS32
+             /* Windows NT defines HOMEDRIVE and HOMEPATH.  But give
+                preference to HOME, because the user can change HOME.  */
+             const char *home_drive = getenv ("HOMEDRIVE");
+             const char *home_path = getenv ("HOMEPATH");
+
+             if (home_drive != NULL && home_path != NULL)
+               {
+                 size_t home_drive_len = strlen (home_drive);
+                 size_t home_path_len = strlen (home_path);
+                 char *mem = alloca (home_drive_len + home_path_len + 1);
+
+                 memcpy (mem, home_drive, home_drive_len);
+                 memcpy (mem + home_drive_len, home_path, home_path_len + 1);
+                 home_dir = mem;
+               }
+             else
+               home_dir = "c:/users/default"; /* poor default */
+#else
              int success;
              char *name;
+             int malloc_name = 0;
              size_t buflen = GET_LOGIN_NAME_MAX () + 1;
 
              if (buflen == 0)
-               /* `sysconf' does not support _SC_LOGIN_NAME_MAX.  Try
+               /* 'sysconf' does not support _SC_LOGIN_NAME_MAX.  Try
                   a moderate value.  */
                buflen = 20;
-             name = alloca_account (buflen, alloca_used);
+             if (glob_use_alloca (alloca_used, buflen))
+               name = alloca_account (buflen, alloca_used);
+             else
+               {
+                 name = malloc (buflen);
+                 if (name == NULL)
+                   {
+                     retval = GLOB_NOSPACE;
+                     goto out;
+                   }
+                 malloc_name = 1;
+               }
 
              success = __getlogin_r (name, buflen) == 0;
              if (success)
                {
                  struct passwd *p;
-#   if defined HAVE_GETPWNAM_R || defined _LIBC
-                 long int pwbuflen = GETPW_R_SIZE_MAX ();
+                 char *malloc_pwtmpbuf = NULL;
                  char *pwtmpbuf;
+# if defined HAVE_GETPWNAM_R || defined _LIBC
+                 long int pwbuflenmax = GETPW_R_SIZE_MAX ();
+                 size_t pwbuflen = pwbuflenmax;
                  struct passwd pwbuf;
-                 int malloc_pwtmpbuf = 0;
                  int save = errno;
 
-#    ifndef _LIBC
-                 if (pwbuflen == -1)
-                   /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX.
+#  ifndef _LIBC
+                 if (! (0 < pwbuflenmax && pwbuflenmax <= SIZE_MAX))
+                   /* 'sysconf' does not support _SC_GETPW_R_SIZE_MAX.
                       Try a moderate value.  */
                    pwbuflen = 1024;
-#    endif
-                 if (__libc_use_alloca (alloca_used + pwbuflen))
+#  endif
+                 if (glob_use_alloca (alloca_used, pwbuflen))
                    pwtmpbuf = alloca_account (pwbuflen, alloca_used);
                  else
                    {
                      pwtmpbuf = malloc (pwbuflen);
                      if (pwtmpbuf == NULL)
                        {
+                         if (__glibc_unlikely (malloc_name))
+                           free (name);
                          retval = GLOB_NOSPACE;
                          goto out;
                        }
-                     malloc_pwtmpbuf = 1;
+                     malloc_pwtmpbuf = pwtmpbuf;
                    }
 
                  while (getpwnam_r (name, &pwbuf, pwtmpbuf, pwbuflen, &p)
                         != 0)
                    {
+                     size_t newlen;
+                     bool v;
                      if (errno != ERANGE)
                        {
                          p = NULL;
                          break;
                        }
-
-                     if (!malloc_pwtmpbuf
-                         && __libc_use_alloca (alloca_used
-                                               + 2 * pwbuflen))
+                     v = size_add_wrapv (pwbuflen, pwbuflen, &newlen);
+                     if (!v && malloc_pwtmpbuf == NULL
+                         && glob_use_alloca (alloca_used, newlen))
                        pwtmpbuf = extend_alloca_account (pwtmpbuf, pwbuflen,
-                                                         2 * pwbuflen,
-                                                         alloca_used);
+                                                         newlen, alloca_used);
                      else
                        {
-                         char *newp = realloc (malloc_pwtmpbuf
-                                               ? pwtmpbuf : NULL,
-                                               2 * pwbuflen);
+                         char *newp = (v ? NULL
+                                       : realloc (malloc_pwtmpbuf, newlen));
                          if (newp == NULL)
                            {
-                             if (__glibc_unlikely (malloc_pwtmpbuf))
-                               free (pwtmpbuf);
+                             free (malloc_pwtmpbuf);
+                             if (__glibc_unlikely (malloc_name))
+                               free (name);
                              retval = GLOB_NOSPACE;
                              goto out;
                            }
-                         pwtmpbuf = newp;
-                         pwbuflen = 2 * pwbuflen;
-                         malloc_pwtmpbuf = 1;
+                         malloc_pwtmpbuf = pwtmpbuf = newp;
                        }
+                     pwbuflen = newlen;
                      __set_errno (save);
                    }
-#   else
+# else
                  p = getpwnam (name);
-#   endif
+# endif
+                 if (__glibc_unlikely (malloc_name))
+                   free (name);
                  if (p != NULL)
                    {
-                     if (!malloc_pwtmpbuf)
+                     if (malloc_pwtmpbuf == NULL)
                        home_dir = p->pw_dir;
                      else
                        {
                          size_t home_dir_len = strlen (p->pw_dir) + 1;
-                         if (__libc_use_alloca (alloca_used + home_dir_len))
+                         if (glob_use_alloca (alloca_used, home_dir_len))
                            home_dir = alloca_account (home_dir_len,
                                                       alloca_used);
                          else
@@ -720,26 +739,32 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
                              malloc_home_dir = 1;
                            }
                          memcpy (home_dir, p->pw_dir, home_dir_len);
-
-                         free (pwtmpbuf);
                        }
                    }
+                 free (malloc_pwtmpbuf);
                }
+             else
+               {
+                 if (__glibc_unlikely (malloc_name))
+                   free (name);
+               }
+#endif /* WINDOWS32 */
            }
          if (home_dir == NULL || home_dir[0] == '\0')
            {
+             if (__glibc_unlikely (malloc_home_dir))
+               free (home_dir);
              if (flags & GLOB_TILDE_CHECK)
                {
-                 if (__glibc_unlikely (malloc_home_dir))
-                   free (home_dir);
                  retval = GLOB_NOMATCH;
                  goto out;
                }
              else
-               home_dir = (char *) "~"; /* No luck.  */
+               {
+                 home_dir = (char *) "~"; /* No luck.  */
+                 malloc_home_dir = 0;
+               }
            }
-#  endif /* WINDOWS32 */
-# endif
          /* Now construct the full directory.  */
          if (dirname[1] == '\0')
            {
@@ -754,8 +779,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
            {
              char *newp;
              size_t home_len = strlen (home_dir);
-             int use_alloca = __libc_use_alloca (alloca_used
-                                                 + home_len + dirlen);
+             int use_alloca = glob_use_alloca (alloca_used, home_len + dirlen);
              if (use_alloca)
                newp = alloca_account (home_len + dirlen, alloca_used);
              else
@@ -779,12 +803,15 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
              dirname = newp;
              dirlen += home_len - 1;
              malloc_dirname = !use_alloca;
+
+             if (__glibc_unlikely (malloc_home_dir))
+               free (home_dir);
            }
          dirname_modified = 1;
        }
-# if !defined _AMIGA && !defined WINDOWS32
       else
        {
+#ifndef WINDOWS32
          char *end_name = strchr (dirname, '/');
          char *user_name;
          int malloc_user_name = 0;
@@ -806,7 +833,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
          else
            {
              char *newp;
-             if (__libc_use_alloca (alloca_used + (end_name - dirname)))
+             if (glob_use_alloca (alloca_used, end_name - dirname))
                newp = alloca_account (end_name - dirname, alloca_used);
              else
                {
@@ -823,11 +850,11 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
                  char *p = mempcpy (newp, dirname + 1,
                                     unescape - dirname - 1);
                  char *q = unescape;
-                 while (*q != '\0')
+                 while (q != end_name)
                    {
                      if (*q == '\\')
                        {
-                         if (q[1] == '\0')
+                         if (q + 1 == end_name)
                            {
                              /* "~fo\\o\\" unescape to user_name "foo\\",
                                 but "~fo\\o\\/" unescape to user_name
@@ -843,7 +870,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
                  *p = '\0';
                }
              else
-               *((char *) mempcpy (newp, dirname + 1, end_name - dirname))
+               *((char *) mempcpy (newp, dirname + 1, end_name - dirname - 1))
                  = '\0';
              user_name = newp;
            }
@@ -851,20 +878,21 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
          /* Look up specific user's home directory.  */
          {
            struct passwd *p;
+           char *malloc_pwtmpbuf = NULL;
 #  if defined HAVE_GETPWNAM_R || defined _LIBC
-           long int buflen = GETPW_R_SIZE_MAX ();
+           long int buflenmax = GETPW_R_SIZE_MAX ();
+           size_t buflen = buflenmax;
            char *pwtmpbuf;
-           int malloc_pwtmpbuf = 0;
            struct passwd pwbuf;
            int save = errno;
 
 #   ifndef _LIBC
-           if (buflen == -1)
-             /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX.  Try a
+           if (! (0 <= buflenmax && buflenmax <= SIZE_MAX))
+             /* Perhaps 'sysconf' does not support _SC_GETPW_R_SIZE_MAX.  Try a
                 moderate value.  */
              buflen = 1024;
 #   endif
-           if (__libc_use_alloca (alloca_used + buflen))
+           if (glob_use_alloca (alloca_used, buflen))
              pwtmpbuf = alloca_account (buflen, alloca_used);
            else
              {
@@ -877,32 +905,32 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
                    retval = GLOB_NOSPACE;
                    goto out;
                  }
-               malloc_pwtmpbuf = 1;
+               malloc_pwtmpbuf = pwtmpbuf;
              }
 
            while (getpwnam_r (user_name, &pwbuf, pwtmpbuf, buflen, &p) != 0)
              {
+               size_t newlen;
+               bool v;
                if (errno != ERANGE)
                  {
                    p = NULL;
                    break;
                  }
-               if (!malloc_pwtmpbuf
-                   && __libc_use_alloca (alloca_used + 2 * buflen))
+               v = size_add_wrapv (buflen, buflen, &newlen);
+               if (!v && malloc_pwtmpbuf == NULL
+                   && glob_use_alloca (alloca_used, newlen))
                  pwtmpbuf = extend_alloca_account (pwtmpbuf, buflen,
-                                                   2 * buflen, alloca_used);
+                                                   newlen, alloca_used);
                else
                  {
-                   char *newp = realloc (malloc_pwtmpbuf ? pwtmpbuf : NULL,
-                                         2 * buflen);
+                   char *newp = v ? NULL : realloc (malloc_pwtmpbuf, newlen);
                    if (newp == NULL)
                      {
-                       if (__glibc_unlikely (malloc_pwtmpbuf))
-                         free (pwtmpbuf);
+                       free (malloc_pwtmpbuf);
                        goto nomem_getpw;
                      }
-                   pwtmpbuf = newp;
-                   malloc_pwtmpbuf = 1;
+                   malloc_pwtmpbuf = pwtmpbuf = newp;
                  }
                __set_errno (save);
              }
@@ -923,7 +951,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
                  free (dirname);
                malloc_dirname = 0;
 
-               if (__libc_use_alloca (alloca_used + home_len + rest_len + 1))
+               if (glob_use_alloca (alloca_used, home_len + rest_len + 1))
                  dirname = alloca_account (home_len + rest_len + 1,
                                            alloca_used);
                else
@@ -931,8 +959,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
                    dirname = malloc (home_len + rest_len + 1);
                    if (dirname == NULL)
                      {
-                       if (__glibc_unlikely (malloc_pwtmpbuf))
-                         free (pwtmpbuf);
+                       free (malloc_pwtmpbuf);
                        retval = GLOB_NOSPACE;
                        goto out;
                      }
@@ -944,24 +971,24 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
                dirlen = home_len + rest_len;
                dirname_modified = 1;
 
-               if (__glibc_unlikely (malloc_pwtmpbuf))
-                 free (pwtmpbuf);
+               free (malloc_pwtmpbuf);
              }
            else
              {
-               if (__glibc_unlikely (malloc_pwtmpbuf))
-                 free (pwtmpbuf);
+               free (malloc_pwtmpbuf);
 
                if (flags & GLOB_TILDE_CHECK)
-                 /* We have to regard it as an error if we cannot find the
-                    home directory.  */
-                 return GLOB_NOMATCH;
+                 {
+                   /* We have to regard it as an error if we cannot find the
+                      home directory.  */
+                   retval = GLOB_NOMATCH;
+                   goto out;
+                 }
              }
          }
+#endif /* !WINDOWS32 */
        }
-# endif        /* Not Amiga && not WINDOWS32.  */
     }
-#endif /* Not VMS.  */
 
   /* Now test whether we looked for "~" or "~NAME".  In this case we
      can give the answer now.  */
@@ -980,19 +1007,18 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
          size_t newcount = pglob->gl_pathc + pglob->gl_offs;
          char **new_gl_pathv;
 
-         if (newcount > UINTPTR_MAX - (1 + 1)
-             || newcount + 1 + 1 > ~((size_t) 0) / sizeof (char *))
+         if (newcount > SIZE_MAX / sizeof (char *) - 2)
            {
            nospace:
              free (pglob->gl_pathv);
              pglob->gl_pathv = NULL;
              pglob->gl_pathc = 0;
-             return GLOB_NOSPACE;
+             retval = GLOB_NOSPACE;
+             goto out;
            }
 
-         new_gl_pathv
-           = (char **) realloc (pglob->gl_pathv,
-                                (newcount + 1 + 1) * sizeof (char *));
+         new_gl_pathv = realloc (pglob->gl_pathv,
+                                 (newcount + 2) * sizeof (char *));
          if (new_gl_pathv == NULL)
            goto nospace;
          pglob->gl_pathv = new_gl_pathv;
@@ -1006,12 +1032,19 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
              p = mempcpy (pglob->gl_pathv[newcount], dirname, dirlen);
              p[0] = '/';
              p[1] = '\0';
+             if (__glibc_unlikely (malloc_dirname))
+               free (dirname);
            }
          else
            {
-             pglob->gl_pathv[newcount] = strdup (dirname);
-             if (pglob->gl_pathv[newcount] == NULL)
-               goto nospace;
+             if (__glibc_unlikely (malloc_dirname))
+               pglob->gl_pathv[newcount] = dirname;
+             else
+               {
+                 pglob->gl_pathv[newcount] = strdup (dirname);
+                 if (pglob->gl_pathv[newcount] == NULL)
+                   goto nospace;
+               }
            }
          pglob->gl_pathv[++newcount] = NULL;
          ++pglob->gl_pathc;
@@ -1021,7 +1054,8 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
        }
 
       /* Not found.  */
-      return GLOB_NOMATCH;
+      retval = GLOB_NOMATCH;
+      goto out;
     }
 
   meta = __glob_pattern_type (dirname, !(flags & GLOB_NOESCAPE));
@@ -1067,7 +1101,10 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
       if (status != 0)
        {
          if ((flags & GLOB_NOCHECK) == 0 || status != GLOB_NOMATCH)
-           return status;
+           {
+             retval = status;
+             goto out;
+           }
          goto no_matches;
        }
 
@@ -1078,19 +1115,6 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
        {
          size_t old_pathc;
 
-#ifdef SHELL
-         {
-           /* Make globbing interruptible in the bash shell. */
-           extern int interrupt_state;
-
-           if (interrupt_state)
-             {
-               globfree (&dirs);
-               return GLOB_ABORTED;
-             }
-         }
-#endif /* SHELL.  */
-
          old_pathc = pglob->gl_pathc;
          status = glob_in_dir (filename, dirs.gl_pathv[i],
                                ((flags | GLOB_APPEND)
@@ -1105,7 +1129,8 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
              globfree (&dirs);
              globfree (pglob);
              pglob->gl_pathc = 0;
-             return status;
+             retval = status;
+             goto out;
            }
 
          /* Stick the directory on the front of each name.  */
@@ -1116,13 +1141,14 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
              globfree (&dirs);
              globfree (pglob);
              pglob->gl_pathc = 0;
-             return GLOB_NOSPACE;
+             retval = GLOB_NOSPACE;
+             goto out;
            }
        }
 
       flags |= GLOB_MAGCHAR;
 
-      /* We have ignored the GLOB_NOCHECK flag in the `glob_in_dir' calls.
+      /* We have ignored the GLOB_NOCHECK flag in the 'glob_in_dir' calls.
         But if we have not found any matching entry and the GLOB_NOCHECK
         flag was set we must return the input pattern itself.  */
       if (pglob->gl_pathc + pglob->gl_offs == oldcount)
@@ -1134,28 +1160,28 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
              size_t newcount = pglob->gl_pathc + pglob->gl_offs;
              char **new_gl_pathv;
 
-             if (newcount > UINTPTR_MAX - 2
-                 || newcount + 2 > ~((size_t) 0) / sizeof (char *))
+             if (newcount > SIZE_MAX / sizeof (char *) - 2)
                {
                nospace2:
                  globfree (&dirs);
-                 return GLOB_NOSPACE;
+                 retval = GLOB_NOSPACE;
+                 goto out;
                }
 
-             new_gl_pathv = (char **) realloc (pglob->gl_pathv,
-                                               (newcount + 2)
-                                               * sizeof (char *));
+             new_gl_pathv = realloc (pglob->gl_pathv,
+                                     (newcount + 2) * sizeof (char *));
              if (new_gl_pathv == NULL)
                goto nospace2;
              pglob->gl_pathv = new_gl_pathv;
 
-             pglob->gl_pathv[newcount] = __strdup (pattern);
+             pglob->gl_pathv[newcount] = strdup (pattern);
              if (pglob->gl_pathv[newcount] == NULL)
                {
                  globfree (&dirs);
                  globfree (pglob);
                  pglob->gl_pathc = 0;
-                 return GLOB_NOSPACE;
+                 retval = GLOB_NOSPACE;
+                 goto out;
                }
 
              ++pglob->gl_pathc;
@@ -1167,7 +1193,8 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
          else
            {
              globfree (&dirs);
-             return GLOB_NOMATCH;
+             retval = GLOB_NOMATCH;
+             goto out;
            }
        }
 
@@ -1213,7 +1240,8 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
              flags = orig_flags;
              goto no_matches;
            }
-         return status;
+         retval = status;
+         goto out;
        }
 
       if (dirlen > 0)
@@ -1225,7 +1253,8 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
            {
              globfree (pglob);
              pglob->gl_pathc = 0;
-             return GLOB_NOSPACE;
+             retval = GLOB_NOSPACE;
+             goto out;
            }
        }
     }
@@ -1250,7 +1279,8 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
              {
                globfree (pglob);
                pglob->gl_pathc = 0;
-               return GLOB_NOSPACE;
+               retval = GLOB_NOSPACE;
+               goto out;
              }
            strcpy (&new[len - 2], "/");
            pglob->gl_pathv[i] = new;
@@ -1276,32 +1306,12 @@ libc_hidden_def (glob)
 #endif
 
 
-#if !defined _LIBC || !defined GLOB_ONLY_P
-
-/* Free storage allocated in PGLOB by a previous `glob' call.  */
-void
-globfree (glob_t *pglob)
-{
-  if (pglob->gl_pathv != NULL)
-    {
-      size_t i;
-      for (i = 0; i < pglob->gl_pathc; ++i)
-       free (pglob->gl_pathv[pglob->gl_offs + i]);
-      free (pglob->gl_pathv);
-      pglob->gl_pathv = NULL;
-    }
-}
-#if defined _LIBC && !defined globfree
-libc_hidden_def (globfree)
-#endif
-
-
 /* Do a collated comparison of A and B.  */
 static int
 collated_compare (const void *a, const void *b)
 {
-  const char *const s1 = *(const char *const * const) a;
-  const char *const s2 = *(const char *const * const) b;
+  char *const *ps1 = a; char *s1 = *ps1;
+  char *const *ps2 = b; char *s2 = *ps2;
 
   if (s1 == s2)
     return 0;
@@ -1322,28 +1332,24 @@ prefix_array (const char *dirname, char **array, size_t n)
 {
   size_t i;
   size_t dirlen = strlen (dirname);
-#if defined __MSDOS__ || defined WINDOWS32
-  int sep_char = '/';
-# define DIRSEP_CHAR sep_char
-#else
-# define DIRSEP_CHAR '/'
-#endif
+  char dirsep_char = '/';
 
   if (dirlen == 1 && dirname[0] == '/')
     /* DIRNAME is just "/", so normal prepending would get us "//foo".
        We want "/foo" instead, so don't prepend any chars from DIRNAME.  */
     dirlen = 0;
+
 #if defined __MSDOS__ || defined WINDOWS32
-  else if (dirlen > 1)
+  if (dirlen > 1)
     {
       if (dirname[dirlen - 1] == '/' && dirname[dirlen - 2] == ':')
        /* DIRNAME is "d:/".  Don't prepend the slash from DIRNAME.  */
        --dirlen;
       else if (dirname[dirlen - 1] == ':')
        {
-         /* DIRNAME is "d:".  Use `:' instead of `/'.  */
+         /* DIRNAME is "d:".  Use ':' instead of '/'.  */
          --dirlen;
-         sep_char = ':';
+         dirsep_char = ':';
        }
     }
 #endif
@@ -1351,7 +1357,7 @@ prefix_array (const char *dirname, char **array, size_t n)
   for (i = 0; i < n; ++i)
     {
       size_t eltlen = strlen (array[i]) + 1;
-      char *new = (char *) malloc (dirlen + 1 + eltlen);
+      char *new = malloc (dirlen + 1 + eltlen);
       if (new == NULL)
        {
          while (i > 0)
@@ -1361,7 +1367,7 @@ prefix_array (const char *dirname, char **array, size_t n)
 
       {
        char *endp = mempcpy (new, dirname, dirlen);
-       *endp++ = DIRSEP_CHAR;
+       *endp++ = dirsep_char;
        mempcpy (endp, array[i], eltlen);
       }
       free (array[i]);
@@ -1371,103 +1377,57 @@ prefix_array (const char *dirname, char **array, size_t n)
   return 0;
 }
 
-
-/* We must not compile this function twice.  */
-#if !defined _LIBC || !defined NO_GLOB_PATTERN_P
-int
-__glob_pattern_type (const char *pattern, int quote)
-{
-  const char *p;
-  int ret = 0;
-
-  for (p = pattern; *p != '\0'; ++p)
-    switch (*p)
-      {
-      case '?':
-      case '*':
-       return 1;
-
-      case '\\':
-       if (quote)
-         {
-           if (p[1] != '\0')
-             ++p;
-           ret |= 2;
-         }
-       break;
-
-      case '[':
-       ret |= 4;
-       break;
-
-      case ']':
-       if (ret & 4)
-         return 1;
-       break;
-      }
-
-  return ret;
-}
-
-/* Return nonzero if PATTERN contains any metacharacters.
-   Metacharacters can be quoted with backslashes if QUOTE is nonzero.  */
-int
-__glob_pattern_p (const char *pattern, int quote)
-{
-  return __glob_pattern_type (pattern, quote) == 1;
-}
-# ifdef _LIBC
-weak_alias (__glob_pattern_p, glob_pattern_p)
-# endif
-#endif
-
-#endif /* !GLOB_ONLY_P */
-
-
 /* We put this in a separate function mainly to allow the memory
    allocated with alloca to be recycled.  */
-#if !defined _LIBC || !defined GLOB_ONLY_P
 static int
 __attribute_noinline__
-link_exists2_p (const char *dir, size_t dirlen, const char *fname,
-              glob_t *pglob
-# ifndef _LIBC
-               , int flags
+link_stat (const char *dir, size_t dirlen, const char *fname,
+          glob_t *pglob
+# if !defined _LIBC && !HAVE_FSTATAT
+          , int flags
 # endif
-               )
+          )
 {
   size_t fnamelen = strlen (fname);
-  char *fullname = (char *) __alloca (dirlen + 1 + fnamelen + 1);
+  char *fullname = __alloca (dirlen + 1 + fnamelen + 1);
   struct stat st;
-# ifndef _LIBC
-  struct_stat64 st64;
-# endif
 
   mempcpy (mempcpy (mempcpy (fullname, dir, dirlen), "/", 1),
           fname, fnamelen + 1);
 
-# ifdef _LIBC
-  return (*pglob->gl_stat) (fullname, &st) == 0;
-# else
-  return ((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
-          ? (*pglob->gl_stat) (fullname, &st)
-          : __stat64 (fullname, &st64)) == 0);
+# if !defined _LIBC && !HAVE_FSTATAT
+  if (__builtin_expect ((flags & GLOB_ALTDIRFUNC) == 0, 1))
+    {
+      struct_stat64 st64;
+      return __stat64 (fullname, &st64);
+    }
 # endif
+  return (*pglob->gl_stat) (fullname, &st);
 }
-# ifdef _LIBC
-#  define link_exists_p(dfd, dirname, dirnamelen, fname, pglob, flags) \
-  (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)                             \
-   ? link_exists2_p (dirname, dirnamelen, fname, pglob)                              \
-   : ({ struct stat64 st64;                                                  \
-       __fxstatat64 (_STAT_VER, dfd, fname, &st64, 0) == 0; }))
+
+/* Return true if DIR/FNAME exists.  */
+static int
+link_exists_p (int dfd, const char *dir, size_t dirlen, const char *fname,
+              glob_t *pglob, int flags)
+{
+  int status;
+# if defined _LIBC || HAVE_FSTATAT
+  if (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0))
+    status = link_stat (dir, dirlen, fname, pglob);
+  else
+    {
+      /* dfd cannot be -1 here, because dirfd never returns -1 on
+        glibc, or on hosts that have fstatat.  */
+      struct_stat64 st64;
+      status = __fxstatat64 (_STAT_VER, dfd, fname, &st64, 0);
+    }
 # else
-#  define link_exists_p(dfd, dirname, dirnamelen, fname, pglob, flags) \
-  link_exists2_p (dirname, dirnamelen, fname, pglob, flags)
+  status = link_stat (dir, dirlen, fname, pglob, flags);
 # endif
-#endif
-
+  return status == 0 || errno == EOVERFLOW;
+}
 
-/* Like `glob', but PATTERN is a final pathname component,
+/* Like 'glob', but PATTERN is a final pathname component,
    and matches are searched for in DIRECTORY.
    The GLOB_NOSORT bit in FLAGS is ignored.  No sorting is ever done.
    The GLOB_APPEND flag is assumed to be set (always appends).  */
@@ -1478,25 +1438,25 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
 {
   size_t dirlen = strlen (directory);
   void *stream = NULL;
-  struct globnames
-    {
-      struct globnames *next;
-      size_t count;
-      char *name[64];
-    };
-#define INITIAL_COUNT sizeof (init_names.name) / sizeof (init_names.name[0])
-  struct globnames init_names;
-  struct globnames *names = &init_names;
-  struct globnames *names_alloca = &init_names;
+# define GLOBNAMES_MEMBERS(nnames) \
+    struct globnames *next; size_t count; char *name[nnames];
+  struct globnames { GLOBNAMES_MEMBERS (FLEXIBLE_ARRAY_MEMBER) };
+  struct { GLOBNAMES_MEMBERS (64) } init_names_buf;
+  struct globnames *init_names = (struct globnames *) &init_names_buf;
+  struct globnames *names = init_names;
+  struct globnames *names_alloca = init_names;
   size_t nfound = 0;
   size_t cur = 0;
   int meta;
   int save;
+  int result;
 
-  alloca_used += sizeof (init_names);
+  alloca_used += sizeof init_names_buf;
 
-  init_names.next = NULL;
-  init_names.count = INITIAL_COUNT;
+  init_names->next = NULL;
+  init_names->count = ((sizeof init_names_buf
+                        - offsetof (struct globnames, name))
+                       / sizeof init_names->name[0]);
 
   meta = __glob_pattern_type (pattern, !(flags & GLOB_NOESCAPE));
   if (meta == 0 && (flags & (GLOB_NOCHECK|GLOB_NOMAGIC)))
@@ -1516,14 +1476,16 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
        struct_stat64 st64;
       } ust;
       size_t patlen = strlen (pattern);
-      int alloca_fullname = __libc_use_alloca (alloca_used
-                                              + dirlen + 1 + patlen + 1);
+      size_t fullsize;
+      bool alloca_fullname
+        = (! size_add_wrapv (dirlen + 1, patlen + 1, &fullsize)
+           && glob_use_alloca (alloca_used, fullsize));
       char *fullname;
       if (alloca_fullname)
-       fullname = alloca_account (dirlen + 1 + patlen + 1, alloca_used);
+        fullname = alloca_account (fullsize, alloca_used);
       else
        {
-         fullname = malloc (dirlen + 1 + patlen + 1);
+         fullname = malloc (fullsize);
          if (fullname == NULL)
            return GLOB_NOSPACE;
        }
@@ -1531,9 +1493,11 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
       mempcpy (mempcpy (mempcpy (fullname, directory, dirlen),
                        "/", 1),
               pattern, patlen + 1);
-      if ((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
+      if (((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
           ? (*pglob->gl_stat) (fullname, &ust.st)
-          : __stat64 (fullname, &ust.st64)) == 0)
+           : __stat64 (fullname, &ust.st64))
+          == 0)
+         || errno == EOVERFLOW)
        /* We found this file to be existing.  Now tell the rest
           of the function to copy this name into the result.  */
        flags |= GLOB_NOCHECK;
@@ -1555,16 +1519,10 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
        }
       else
        {
-#ifdef _LIBC
          int dfd = (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
                     ? -1 : dirfd ((DIR *) stream));
-#endif
          int fnm_flags = ((!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0)
-                          | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0)
-#if defined _AMIGA || defined VMS
-                          | FNM_CASEFOLD
-#endif
-                          );
+                          | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0));
          flags |= GLOB_MAGCHAR;
 
          while (1)
@@ -1584,19 +1542,24 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
              }
              if (d.name == NULL)
                break;
-             if (d.skip_entry)
+             if (readdir_result_skip_entry (d))
                continue;
 
              /* If we shall match only directories use the information
                 provided by the dirent call if possible.  */
-             if ((flags & GLOB_ONLYDIR) && !readdir_result_might_be_dir (d))
-               continue;
+             if (flags & GLOB_ONLYDIR)
+               switch (readdir_result_type (d))
+                 {
+                 case DT_DIR: case DT_LNK: case DT_UNKNOWN: break;
+                 default: continue;
+                 }
 
              if (fnmatch (pattern, d.name, fnm_flags) == 0)
                {
                  /* If the file we found is a symlink we have to
                     make sure the target file exists.  */
-                 if (!readdir_result_might_be_symlink (d)
+                 dirent_type type = readdir_result_type (d);
+                 if (! (type == DT_LNK || type == DT_UNKNOWN)
                      || link_exists_p (dfd, directory, dirlen, d.name,
                                        pglob, flags))
                    {
@@ -1604,10 +1567,13 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
                        {
                          struct globnames *newnames;
                          size_t count = names->count * 2;
-                         size_t size = (sizeof (struct globnames)
-                                        + ((count - INITIAL_COUNT)
-                                           * sizeof (char *)));
-                         if (__libc_use_alloca (alloca_used + size))
+                         size_t nameoff = offsetof (struct globnames, name);
+                         size_t size = FLEXSIZEOF (struct globnames, name,
+                                                   count * sizeof (char *));
+                         if ((SIZE_MAX - nameoff) / 2 / sizeof (char *)
+                             < names->count)
+                           goto memory_error;
+                         if (glob_use_alloca (alloca_used, size))
                            newnames = names_alloca
                              = alloca_account (size, alloca_used);
                          else if ((newnames = malloc (size))
@@ -1623,6 +1589,8 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
                        goto memory_error;
                      ++cur;
                      ++nfound;
+                     if (SIZE_MAX - pglob->gl_offs <= nfound)
+                       goto memory_error;
                    }
                }
            }
@@ -1633,29 +1601,27 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
     {
       size_t len = strlen (pattern);
       nfound = 1;
-      names->name[cur] = (char *) malloc (len + 1);
+      names->name[cur] = malloc (len + 1);
       if (names->name[cur] == NULL)
        goto memory_error;
       *((char *) mempcpy (names->name[cur++], pattern, len)) = '\0';
     }
 
-  int result = GLOB_NOMATCH;
+  result = GLOB_NOMATCH;
   if (nfound != 0)
     {
+      char **new_gl_pathv;
       result = 0;
 
-      if (pglob->gl_pathc > UINTPTR_MAX - pglob->gl_offs
-         || pglob->gl_pathc + pglob->gl_offs > UINTPTR_MAX - nfound
-         || pglob->gl_pathc + pglob->gl_offs + nfound > UINTPTR_MAX - 1
-         || (pglob->gl_pathc + pglob->gl_offs + nfound + 1
-             > UINTPTR_MAX / sizeof (char *)))
+      if (SIZE_MAX / sizeof (char *) - pglob->gl_pathc
+         < pglob->gl_offs + nfound + 1)
        goto memory_error;
 
-      char **new_gl_pathv;
       new_gl_pathv
-       = (char **) realloc (pglob->gl_pathv,
-                            (pglob->gl_pathc + pglob->gl_offs + nfound + 1)
-                            * sizeof (char *));
+       = realloc (pglob->gl_pathv,
+                  (pglob->gl_pathc + pglob->gl_offs + nfound + 1)
+                   * sizeof (char *));
+
       if (new_gl_pathv == NULL)
        {
        memory_error:
@@ -1671,7 +1637,7 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
                 and this is the block assigned to OLD here.  */
              if (names == NULL)
                {
-                 assert (old == &init_names);
+                 assert (old == init_names);
                  break;
                }
              cur = names->count;
@@ -1697,7 +1663,7 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
                 and this is the block assigned to OLD here.  */
              if (names == NULL)
                {
-                 assert (old == &init_names);
+                 assert (old == init_names);
                  break;
                }
              cur = names->count;
index 6cb3d654a8f42edcd0197af8fe33101338789c91..a515a1c12f39d84bd20e48bedc04efee4f5a7ea6 100644 (file)
@@ -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 (file)
index 0000000..12c9366
--- /dev/null
@@ -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
+   <http://www.gnu.org/licenses/>.  */
+
+#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 (file)
index 0000000..a17d337
--- /dev/null
@@ -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
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _LIBC
+# include <config.h>
+#endif
+
+#include <glob.h>
+#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 (file)
index 0000000..042e29d
--- /dev/null
@@ -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
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _LIBC
+# include <config.h>
+#endif
+
+#include <glob.h>
+#include <stdlib.h>
+
+/* Free storage allocated in PGLOB by a previous `glob' call.  */
+void
+globfree (glob_t *pglob)
+{
+  if (pglob->gl_pathv != NULL)
+    {
+      size_t i;
+      for (i = 0; i < pglob->gl_pathc; ++i)
+        free (pglob->gl_pathv[pglob->gl_offs + i]);
+      free (pglob->gl_pathv);
+      pglob->gl_pathv = NULL;
+    }
+}
+#ifndef globfree
+libc_hidden_def (globfree)
+#endif
diff --git a/posix/globfree64.c b/posix/globfree64.c
new file mode 100644 (file)
index 0000000..c9f8908
--- /dev/null
@@ -0,0 +1,31 @@
+/* Frees the dynamically allocated storage from an earlier call to glob.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _LIBC
+# include <config.h>
+#endif
+
+#include <glob.h>
+#include <stdlib.h>
+
+/* Free storage allocated in PGLOB by a previous `glob' call.  */
+void
+globfree64 (glob64_t *pglob)
+{
+}
+libc_hidden_def (globfree64)
index f9cc80b4b58e1e2fd2d5bb496d2e6aa549676ed8..73f7ae31cca138a78b70e0974a904cec09f56bfd 100755 (executable)
@@ -47,7 +47,12 @@ testout=${common_objpfx}posix/globtest-out
 rm -rf $testdir $testout
 mkdir $testdir
 
-trap 'chmod 777 $testdir/noread; rm -fr $testdir $testout' 1 2 3 15
+cleanup() {
+    chmod 777 $testdir/noread
+    rm -fr $testdir $testout
+}
+
+trap cleanup 0 HUP INT QUIT TERM
 
 echo 1 > $testdir/file1
 echo 2 > $testdir/file2
@@ -811,8 +816,6 @@ if test $failed -ne 0; then
 fi
 
 if test $result -eq 0; then
-    chmod 777 $testdir/noread
-    rm -fr $testdir $testout
     echo "All OK." > $logfile
 fi
 
diff --git a/posix/tst-glob-tilde.c b/posix/tst-glob-tilde.c
new file mode 100644 (file)
index 0000000..6886f43
--- /dev/null
@@ -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
+   <http://www.gnu.org/licenses/>.  */
+
+#include <glob.h>
+#include <mcheck.h>
+#include <nss.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/support.h>
+
+/* 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 <support/test-driver.c>
index fdc37edff16baf1fd62b46ecccd3180372017c78..01086d569f58170a2483e91c9fd91de5cba2e6c3 100644 (file)
@@ -46,6 +46,7 @@ tests += \
   tst-res_hconf_reorder \
   tst-res_use_inet6 \
   tst-resolv-basic \
+  tst-resolv-edns \
   tst-resolv-network \
   tst-resolv-search \
 
@@ -124,6 +125,7 @@ $(objpfx)tst-bug18665-tcp: $(objpfx)libresolv.so $(shared-thread-library)
 $(objpfx)tst-bug18665: $(objpfx)libresolv.so $(shared-thread-library)
 $(objpfx)tst-res_use_inet6: $(objpfx)libresolv.so $(shared-thread-library)
 $(objpfx)tst-resolv-basic: $(objpfx)libresolv.so $(shared-thread-library)
+$(objpfx)tst-resolv-edns: $(objpfx)libresolv.so $(shared-thread-library)
 $(objpfx)tst-resolv-network: $(objpfx)libresolv.so $(shared-thread-library)
 $(objpfx)tst-resolv-qtypes: $(objpfx)libresolv.so $(shared-thread-library)
 $(objpfx)tst-resolv-search: $(objpfx)libresolv.so $(shared-thread-library)
index d80b5318e5e0cffdc2c65c0db280116f25957ec3..5a0bb1044b55a643b315294457a322cb9099dfb2 100644 (file)
@@ -69,7 +69,7 @@
 #include <netinet/in.h>
 #include <arpa/nameser.h>
 #include <netdb.h>
-#include <resolv.h>
+#include <resolv/resolv-internal.h>
 #include <stdio.h>
 #include <string.h>
 #include <sys/time.h>
@@ -243,7 +243,30 @@ __res_nopt(res_state statp,
        *cp++ = 0;      /* "." */
 
        NS_PUT16(T_OPT, cp);    /* TYPE */
-       NS_PUT16(MIN(anslen, 0xffff), cp);      /* CLASS = UDP payload size */
+
+       /* Lowering the advertised buffer size based on the actual
+          answer buffer size is desirable because the server will
+          minimize the reply to fit into the UDP packet (and A
+          non-minimal response might not fit the buffer).
+
+          The RESOLV_EDNS_BUFFER_SIZE limit could still result in TCP
+          fallback and a non-minimal response which has to be
+          hard-truncated in the stub resolver, but this is price to
+          pay for avoiding fragmentation.  (This issue does not
+          affect the nss_dns functions because they use the stub
+          resolver in such a way that it allocates a properly sized
+          response buffer.)  */
+       {
+         uint16_t buffer_size;
+         if (anslen < 512)
+           buffer_size = 512;
+         else if (anslen > RESOLV_EDNS_BUFFER_SIZE)
+           buffer_size = RESOLV_EDNS_BUFFER_SIZE;
+         else
+           buffer_size = anslen;
+         NS_PUT16 (buffer_size, cp);
+       }
+
        *cp++ = NOERROR;        /* extended RCODE */
        *cp++ = 0;              /* EDNS version */
 
@@ -261,4 +284,3 @@ __res_nopt(res_state statp,
 
        return cp - buf;
 }
-libresolv_hidden_def (__res_nopt)
index 07dc6f658386e5be6744336a5090352033aa9649..57156d01ec3c9fc2169269ac53e1cd4bbb4f5e52 100644 (file)
@@ -77,6 +77,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <resolv/resolv-internal.h>
 
 /* Options.  Leave them on. */
 /* #undef DEBUG */
@@ -146,7 +147,10 @@ __libc_res_nquery(res_state statp,
                if ((oflags & RES_F_EDNS0ERR) == 0
                    && (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0)
                  {
-                   n = __res_nopt(statp, n, query1, bufsize, anslen / 2);
+                   /* Use RESOLV_EDNS_BUFFER_SIZE because the receive
+                      buffer can be reallocated.  */
+                   n = __res_nopt (statp, n, query1, bufsize,
+                                   RESOLV_EDNS_BUFFER_SIZE);
                    if (n < 0)
                      goto unspec_nomem;
                  }
@@ -167,8 +171,10 @@ __libc_res_nquery(res_state statp,
                if (n > 0
                    && (oflags & RES_F_EDNS0ERR) == 0
                    && (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0)
-                 n = __res_nopt(statp, n, query2, bufsize - nused - n,
-                                anslen / 2);
+                 /* Use RESOLV_EDNS_BUFFER_SIZE because the receive
+                    buffer can be reallocated.  */
+                 n = __res_nopt (statp, n, query2, bufsize,
+                                 RESOLV_EDNS_BUFFER_SIZE);
                nquery2 = n;
              }
 
@@ -182,7 +188,16 @@ __libc_res_nquery(res_state statp,
            if (n > 0
                && (oflags & RES_F_EDNS0ERR) == 0
                && (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0)
-             n = __res_nopt(statp, n, query1, bufsize, anslen);
+             {
+               /* Use RESOLV_EDNS_BUFFER_SIZE if the receive buffer
+                  can be reallocated.  */
+               size_t advertise;
+               if (answerp == NULL)
+                 advertise = anslen;
+               else
+                 advertise = RESOLV_EDNS_BUFFER_SIZE;
+               n = __res_nopt (statp, n, query1, bufsize, advertise);
+             }
 
            nquery1 = n;
          }
index 99fc17c609716b40b4842f8496462f9cda9cc65e..76fbe2f1a61b79bb20b39012dacea03ffe856126 100644 (file)
@@ -32,4 +32,22 @@ res_use_inet6 (void)
   return _res.options & DEPRECATED_RES_USE_INET6;
 }
 
+enum
+  {
+    /* The advertized EDNS buffer size.  The value 1200 is derived
+       from the IPv6 minimum MTU (1280 bytes) minus some arbitrary
+       space for tunneling overhead.  If the DNS server does not react
+       to ICMP Fragmentation Needed But DF Set messages, this should
+       avoid all UDP fragments on current networks.  Avoiding UDP
+       fragments is desirable because it prevents fragmentation-based
+       spoofing attacks because the randomness in a DNS packet is
+       concentrated in the first fragment (with the headers) and does
+       not protect subsequent fragments.  */
+    RESOLV_EDNS_BUFFER_SIZE = 1200,
+  };
+
+/* Add an OPT record to a DNS query.  */
+int __res_nopt (res_state, int n0, unsigned char *buf, int buflen,
+                int anslen) attribute_hidden;
+
 #endif  /* _RESOLV_INTERNAL_H */
diff --git a/resolv/tst-resolv-edns.c b/resolv/tst-resolv-edns.c
new file mode 100644 (file)
index 0000000..f17dbc3
--- /dev/null
@@ -0,0 +1,501 @@
+/* Test EDNS handling in the stub resolver.
+   Copyright (C) 2016-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/resolv_test.h>
+#include <support/support.h>
+#include <support/test-driver.h>
+#include <support/xthread.h>
+
+/* Data produced by a test query.  */
+struct response_data
+{
+  char *qname;
+  uint16_t qtype;
+  struct resolv_edns_info edns;
+};
+
+/* Global array used by put_response and get_response to record
+   response data.  The test DNS server returns the index of the array
+   element which contains the actual response data.  This enables the
+   test case to return arbitrary amounts of data with the limited
+   number of bits which fit into an IP addres.
+
+   The volatile specifier is needed because the test case accesses
+   these variables from a callback function called from a function
+   which is marked as __THROW (i.e., a leaf function which actually is
+   not).  */
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+static struct response_data ** volatile response_data_array;
+volatile static size_t response_data_count;
+
+/* Extract information from the query, store it in a struct
+   response_data object, and return its index in the
+   response_data_array.  */
+static unsigned int
+put_response (const struct resolv_response_context *ctx,
+                 const char *qname, uint16_t qtype)
+{
+  xpthread_mutex_lock (&mutex);
+  ++response_data_count;
+  /* We only can represent 2**24 indexes in 10.0.0.0/8.  */
+  TEST_VERIFY (response_data_count < (1 << 24));
+  response_data_array = xrealloc
+    (response_data_array, sizeof (*response_data_array) * response_data_count);
+  unsigned int index = response_data_count - 1;
+  struct response_data *data = xmalloc (sizeof (*data));
+  *data = (struct response_data)
+    {
+      .qname = xstrdup (qname),
+      .qtype = qtype,
+      .edns = ctx->edns,
+    };
+  response_data_array[index] = data;
+  xpthread_mutex_unlock (&mutex);
+  return index;
+}
+
+/* Verify the index into the response_data array and return the data
+   at it.  */
+static struct response_data *
+get_response (unsigned int index)
+{
+  xpthread_mutex_lock (&mutex);
+  TEST_VERIFY_EXIT (index < response_data_count);
+  struct response_data *result = response_data_array[index];
+  xpthread_mutex_unlock (&mutex);
+  return result;
+}
+
+/* Deallocate all response data.  */
+static void
+free_response_data (void)
+{
+  xpthread_mutex_lock (&mutex);
+  size_t count = response_data_count;
+  struct response_data **array = response_data_array;
+  for (unsigned int i = 0; i < count; ++i)
+    {
+      struct response_data *data = array[i];
+      free (data->qname);
+      free (data);
+    }
+  free (array);
+  response_data_array = NULL;
+  response_data_count = 0;
+  xpthread_mutex_unlock (&mutex);
+}
+
+#define EDNS_PROBE_EXAMPLE "edns-probe.example"
+
+static void
+response (const struct resolv_response_context *ctx,
+          struct resolv_response_builder *b,
+          const char *qname, uint16_t qclass, uint16_t qtype)
+{
+  TEST_VERIFY_EXIT (qname != NULL);
+
+  /* The "tcp." prefix can be used to request TCP fallback.  */
+  const char *qname_compare = qname;
+  bool force_tcp;
+  if (strncmp ("tcp.", qname_compare, strlen ("tcp.")) == 0)
+    {
+      force_tcp = true;
+      qname_compare += strlen ("tcp.");
+    }
+  else
+    force_tcp = false;
+
+  enum {edns_probe} requested_qname;
+  if (strcmp (qname_compare, EDNS_PROBE_EXAMPLE) == 0)
+    requested_qname = edns_probe;
+  else
+    {
+      support_record_failure ();
+      printf ("error: unexpected QNAME: %s\n", qname);
+      return;
+    }
+  TEST_VERIFY_EXIT (qclass == C_IN);
+  struct resolv_response_flags flags = {.tc = force_tcp && !ctx->tcp};
+  resolv_response_init (b, flags);
+  resolv_response_add_question (b, qname, qclass, qtype);
+  if (flags.tc)
+    return;
+
+  if (test_verbose)
+    printf ("info: edns=%d payload_size=%d\n",
+            ctx->edns.active, ctx->edns.payload_size);
+
+  /* Encode the response_data object in multiple address records.
+     Each record carries two bytes of payload data, and an index.  */
+  resolv_response_section (b, ns_s_an);
+  switch (requested_qname)
+    {
+    case edns_probe:
+      {
+        unsigned int index = put_response (ctx, qname, qtype);
+        switch (qtype)
+          {
+          case T_A:
+            {
+              uint32_t addr = htonl (0x0a000000 | index);
+              resolv_response_open_record (b, qname, qclass, qtype, 0);
+              resolv_response_add_data (b, &addr, sizeof (addr));
+              resolv_response_close_record (b);
+            }
+            break;
+          case T_AAAA:
+            {
+              char addr[16]
+                = {0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                   index >> 16, index >> 8, index};
+              resolv_response_open_record (b, qname, qclass, qtype, 0);
+              resolv_response_add_data (b, &addr, sizeof (addr));
+              resolv_response_close_record (b);
+            }
+          }
+      }
+      break;
+    }
+}
+
+/* Update *DATA with data from ADDRESS of SIZE.  Set the corresponding
+   flag in SHADOW for each byte written.  */
+static struct response_data *
+decode_address (const void *address, size_t size)
+{
+  switch (size)
+    {
+    case 4:
+      TEST_VERIFY (memcmp (address, "\x0a", 1) == 0);
+      break;
+    case 16:
+      TEST_VERIFY (memcmp (address, "\x20\x01\x0d\xb8", 4) == 0);
+      break;
+    default:
+      FAIL_EXIT1 ("unexpected address size %zu", size);
+    }
+  const unsigned char *addr = address;
+  unsigned int index = addr[size - 3] * 256 * 256
+    + addr[size - 2] * 256
+    + addr[size - 1];
+  return get_response (index);
+}
+
+static struct response_data *
+decode_hostent (struct hostent *e)
+{
+  TEST_VERIFY_EXIT (e != NULL);
+  TEST_VERIFY_EXIT (e->h_addr_list[0] != NULL);
+  TEST_VERIFY (e->h_addr_list[1] == NULL);
+  return decode_address (e->h_addr_list[0], e->h_length);
+}
+
+static struct response_data *
+decode_addrinfo (struct addrinfo *ai, int family)
+{
+  struct response_data *data = NULL;
+  while (ai != NULL)
+    {
+      if (ai->ai_family == family)
+        {
+          struct response_data *new_data;
+          switch (family)
+            {
+            case AF_INET:
+              {
+                struct sockaddr_in *pin = (struct sockaddr_in *) ai->ai_addr;
+                new_data = decode_address (&pin->sin_addr.s_addr, 4);
+              }
+              break;
+            case AF_INET6:
+              {
+                struct sockaddr_in6 *pin = (struct sockaddr_in6 *) ai->ai_addr;
+                new_data = decode_address (&pin->sin6_addr.s6_addr, 16);
+              }
+              break;
+            default:
+              FAIL_EXIT1 ("invalid address family %d", ai->ai_family);
+            }
+          if (data == NULL)
+            data = new_data;
+          else
+            /* Check pointer equality because this should be the same
+               response (same index).  */
+            TEST_VERIFY (data == new_data);
+        }
+      ai = ai->ai_next;
+    }
+  TEST_VERIFY_EXIT (data != NULL);
+  return data;
+}
+
+/* Updated by the main test loop in accordance with what is set in
+   _res.options.  */
+static bool use_edns;
+static bool use_dnssec;
+
+/* Verify the decoded response data against the flags above.  */
+static void
+verify_response_data_payload (struct response_data *data,
+                              size_t expected_payload)
+{
+  bool edns = use_edns || use_dnssec;
+  TEST_VERIFY (data->edns.active == edns);
+  if (!edns)
+    expected_payload = 0;
+  if (data->edns.payload_size != expected_payload)
+    {
+      support_record_failure ();
+      printf ("error: unexpected payload size %d (edns=%d)\n",
+              (int) data->edns.payload_size, edns);
+    }
+  uint16_t expected_flags = 0;
+  if (use_dnssec)
+    expected_flags |= 0x8000;   /* DO flag.  */
+  if (data->edns.flags != expected_flags)
+    {
+      support_record_failure ();
+      printf ("error: unexpected EDNS flags 0x%04x (edns=%d)\n",
+              (int) data->edns.flags, edns);
+    }
+}
+
+/* Same as verify_response_data_payload, but use the default
+   payload.  */
+static void
+verify_response_data (struct response_data *data)
+{
+  verify_response_data_payload (data, 1200);
+}
+
+static void
+check_hostent (struct hostent *e)
+{
+  TEST_VERIFY_EXIT (e != NULL);
+  verify_response_data (decode_hostent (e));
+}
+
+static void
+do_ai (int family)
+{
+  struct addrinfo hints = { .ai_family = family };
+  struct addrinfo *ai;
+  int ret = getaddrinfo (EDNS_PROBE_EXAMPLE, "80", &hints, &ai);
+  TEST_VERIFY_EXIT (ret == 0);
+  switch (family)
+    {
+    case AF_INET:
+    case AF_INET6:
+      verify_response_data (decode_addrinfo (ai, family));
+      break;
+    case AF_UNSPEC:
+      verify_response_data (decode_addrinfo (ai, AF_INET));
+      verify_response_data (decode_addrinfo (ai, AF_INET6));
+      break;
+    default:
+      FAIL_EXIT1 ("invalid address family %d", family);
+    }
+  freeaddrinfo (ai);
+}
+
+enum res_op
+{
+  res_op_search,
+  res_op_query,
+  res_op_querydomain,
+  res_op_nsearch,
+  res_op_nquery,
+  res_op_nquerydomain,
+
+  res_op_last = res_op_nquerydomain,
+};
+
+static const char *
+res_op_string (enum res_op op)
+{
+  switch (op)
+    {
+      case res_op_search:
+        return "res_search";
+      case res_op_query:
+        return "res_query";
+      case res_op_querydomain:
+        return "res_querydomain";
+      case res_op_nsearch:
+        return "res_nsearch";
+      case res_op_nquery:
+        return "res_nquery";
+      case res_op_nquerydomain:
+        return "res_nquerydomain";
+    }
+  FAIL_EXIT1 ("invalid res_op value %d", (int) op);
+}
+
+/* Call libresolv function OP to look up PROBE_NAME, with an answer
+   buffer of SIZE bytes.  Check that the advertised UDP buffer size is
+   in fact EXPECTED_BUFFER_SIZE.  */
+static void
+do_res_search (const char *probe_name, enum res_op op, size_t size,
+               size_t expected_buffer_size)
+{
+  if (test_verbose)
+    printf ("info: testing %s with buffer size %zu\n",
+            res_op_string (op), size);
+  unsigned char *buffer = xmalloc (size);
+  int ret = -1;
+  switch (op)
+    {
+    case res_op_search:
+      ret = res_search (probe_name, C_IN, T_A, buffer, size);
+      break;
+    case res_op_query:
+      ret = res_query (probe_name, C_IN, T_A, buffer, size);
+      break;
+    case res_op_nsearch:
+      ret = res_nsearch (&_res, probe_name, C_IN, T_A, buffer, size);
+      break;
+    case res_op_nquery:
+      ret = res_nquery (&_res, probe_name, C_IN, T_A, buffer, size);
+      break;
+    case res_op_querydomain:
+    case res_op_nquerydomain:
+      {
+        char *example_stripped = xstrdup (probe_name);
+        char *dot_example = strstr (example_stripped, ".example");
+        if (dot_example != NULL && strcmp (dot_example, ".example") == 0)
+          {
+            /* Truncate the domain name.  */
+            *dot_example = '\0';
+            if (op == res_op_querydomain)
+              ret = res_querydomain
+              (example_stripped, "example", C_IN, T_A, buffer, size);
+            else
+              ret = res_nquerydomain
+                (&_res, example_stripped, "example", C_IN, T_A, buffer, size);
+          }
+        else
+          FAIL_EXIT1 ("invalid probe name: %s", probe_name);
+        free (example_stripped);
+      }
+      break;
+    }
+  TEST_VERIFY_EXIT (ret > 12);
+  unsigned char *end = buffer + ret;
+
+  HEADER *hd = (HEADER *) buffer;
+  TEST_VERIFY (ntohs (hd->qdcount) == 1);
+  TEST_VERIFY (ntohs (hd->ancount) == 1);
+  /* Skip over the header.  */
+  unsigned char *p = buffer + sizeof (*hd);
+  /* Skip over the question.  */
+  ret = dn_skipname (p, end);
+  TEST_VERIFY_EXIT (ret > 0);
+  p += ret;
+  TEST_VERIFY_EXIT (end - p >= 4);
+  p += 4;
+  /* Skip over the RNAME and the RR header, but stop at the RDATA
+     length.  */
+  ret = dn_skipname (p, end);
+  TEST_VERIFY_EXIT (ret > 0);
+  p += ret;
+  TEST_VERIFY_EXIT (end - p >= 2 + 2 + 4 + 2 + 4);
+  p += 2 + 2 + 4;
+  /* The IP address should be 4 bytes long.  */
+  TEST_VERIFY_EXIT (p[0] == 0);
+  TEST_VERIFY_EXIT (p[1] == 4);
+  /* Extract the address information.   */
+  p += 2;
+  struct response_data *data = decode_address (p, 4);
+
+  verify_response_data_payload (data, expected_buffer_size);
+
+  free (buffer);
+}
+
+static void
+run_test (const char *probe_name)
+{
+  if (test_verbose)
+    printf ("\ninfo: * use_edns=%d use_dnssec=%d\n",
+            use_edns, use_dnssec);
+  check_hostent (gethostbyname (probe_name));
+  check_hostent (gethostbyname2 (probe_name, AF_INET));
+  check_hostent (gethostbyname2 (probe_name, AF_INET6));
+  do_ai (AF_UNSPEC);
+  do_ai (AF_INET);
+  do_ai (AF_INET6);
+
+  for (int op = 0; op <= res_op_last; ++op)
+    {
+      do_res_search (probe_name, op, 301, 512);
+      do_res_search (probe_name, op, 511, 512);
+      do_res_search (probe_name, op, 512, 512);
+      do_res_search (probe_name, op, 513, 513);
+      do_res_search (probe_name, op, 657, 657);
+      do_res_search (probe_name, op, 1199, 1199);
+      do_res_search (probe_name, op, 1200, 1200);
+      do_res_search (probe_name, op, 1201, 1200);
+      do_res_search (probe_name, op, 65535, 1200);
+    }
+}
+
+static int
+do_test (void)
+{
+  for (int do_edns = 0; do_edns < 2; ++do_edns)
+    for (int do_dnssec = 0; do_dnssec < 2; ++do_dnssec)
+      for (int do_tcp = 0; do_tcp < 2; ++do_tcp)
+        {
+          struct resolv_test *aux = resolv_test_start
+            ((struct resolv_redirect_config)
+             {
+               .response_callback = response,
+                 });
+
+          use_edns = do_edns;
+          if (do_edns)
+            _res.options |= RES_USE_EDNS0;
+          use_dnssec = do_dnssec;
+          if (do_dnssec)
+            _res.options |= RES_USE_DNSSEC;
+
+          char *probe_name = xstrdup (EDNS_PROBE_EXAMPLE);
+          if (do_tcp)
+            {
+              char *n = xasprintf ("tcp.%s", probe_name);
+              free (probe_name);
+              probe_name = n;
+            }
+
+          run_test (probe_name);
+
+          free (probe_name);
+          resolv_test_end (aux);
+        }
+
+  free_response_data ();
+  return 0;
+}
+
+#include <support/test-driver.c>
index dcb39e505ed84d27c8ce923cf962d5877dbc1ff0..da3325f80cfcee3e4e1e7c6d596e0183b6c016fe 100644 (file)
@@ -50,7 +50,7 @@ response (const struct resolv_response_context *ctx,
   resolv_response_close_record (b);
 }
 
-static const const char *domain = "www.example.com";
+static const char domain[] = "www.example.com";
 
 static int
 wrap_res_query (int type, unsigned char *answer, int answer_length)
diff --git a/scripts/backport-support.sh b/scripts/backport-support.sh
new file mode 100644 (file)
index 0000000..2ece7ce
--- /dev/null
@@ -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
+# <http://www.gnu.org/licenses/>.
+
+# 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 <<EOF
+usage: $0 {patch|commit}
+EOF
+    exit 1
+}
+
+if test $# -ne 1 ; then
+    usage
+fi
+
+command="$1"
+
+case "$command" in
+    patch|commit)
+    ;;
+    *)
+       usage
+       ;;
+esac
+
+# The upstream branch to work on.
+branch=origin/master
+
+# The commit which added the support/ directory.
+initial_commit=c23de0aacbeaa7a091609b35764bed931475a16d
+
+# We backport the support directory and this script.  Directories need
+# to end in a /.
+patch_targets="support/ scripts/backport-support.sh"
+
+latest_commit="$(git log --max-count=1 --pretty=format:%H "$branch" -- \
+  $patch_targets)"
+
+# Simplify the branch name somewhat for reporting.
+branch_name="$(echo "$branch" | sed s,^origin/,,)"
+
+command_patch () {
+    cat <<EOF
+This patch creates the contents of the support/ directory up to this
+upstream commit on the $branch_name branch:
+
+EOF
+    git log --max-count=1 "$latest_commit"
+    echo
+    git diff "$initial_commit"^.."$latest_commit" $patch_targets
+    echo "# Before applying the patch, run this command:" >&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
index a71d4cd8f5fe32c5838db61bc176b66c0b5225bb..a88bbf8de3c6888f5d544e2009b8194ce2e70fdd 100644 (file)
@@ -21,7 +21,7 @@
 
 /* Write LENGTH bytes of randomness starting at BUFFER.  Return 0 on
    success and -1 on failure.  */
-ssize_t
+int
 getentropy (void *buffer, size_t length)
 {
   __set_errno (ENOSYS);
index e6726448886882ba9dd06775ae7284fe75d8d448..2cd8686082d3fa3a4db1fde67a75b7780af32451 100644 (file)
@@ -58,8 +58,8 @@
 static int
 do_test (void)
 {
-  int size = sysconf (_SC_PAGESIZE);
-  int nchars = size / sizeof (CHAR);
+  size_t size = sysconf (_SC_PAGESIZE);
+  size_t nchars = size / sizeof (CHAR);
   CHAR *adr;
   CHAR *dest;
   int result = 0;
@@ -80,7 +80,17 @@ do_test (void)
     }
   else
     {
-      int inner, middle, outer;
+      size_t inner, middle, outer, nchars64, max128;
+
+      if (nchars > 64)
+       nchars64 = nchars - 64;
+      else
+       nchars64 = 0;
+
+      if (nchars > 128)
+       max128 = nchars - 128;
+      else
+       max128 = 0;
 
       mprotect (adr, size, PROT_NONE);
       mprotect (adr + 2 * nchars, size, PROT_NONE);
@@ -93,59 +103,65 @@ do_test (void)
       MEMSET (adr, L('T'), nchars);
 
       /* strlen/wcslen test */
-      for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer)
+      for (outer = nchars - 1; outer >= max128; --outer)
        {
-         for (inner = MAX (outer, nchars - 64); inner < nchars; ++inner)
+         for (inner = MAX (outer, nchars64); inner < nchars; ++inner)
            {
              adr[inner] = L('\0');
 
              if (STRLEN (&adr[outer]) != (size_t) (inner - outer))
                {
-                 printf ("%s flunked for outer = %d, inner = %d\n",
+                 printf ("%s flunked for outer = %zu, inner = %zu\n",
                          STRINGIFY (STRLEN), outer, inner);
                  result = 1;
                }
 
              adr[inner] = L('T');
            }
+         if (outer == 0)
+           break;
        }
 
       /* strnlen/wcsnlen test */
-      for (outer = nchars; outer >= MAX (0, nchars - 128); --outer)
+      for (outer = nchars; outer >= max128; --outer)
        {
-         for (inner = MAX (outer, nchars - 64); inner < nchars; ++inner)
+         for (inner = MAX (outer, nchars64); inner < nchars; ++inner)
            {
              adr[inner] = L('\0');
 
              if (STRNLEN (&adr[outer], inner - outer + 1)
                  != (size_t) (inner - outer))
                {
-                 printf ("%s flunked for outer = %d, inner = %d\n",
+                 printf ("%s flunked for outer = %zu, inner = %zu\n",
                          STRINGIFY (STRNLEN), outer, inner);
                  result = 1;
                }
 
              adr[inner] = L('T');
            }
+         if (outer == 0)
+           break;
        }
-      for (outer = nchars; outer >= MAX (0, nchars - 128); --outer)
+      for (outer = nchars; outer >= max128; --outer)
        {
-         for (inner = MAX (outer, nchars - 64); inner <= nchars; ++inner)
+         for (inner = MAX (outer, nchars64); inner <= nchars; ++inner)
            {
              if (STRNLEN (&adr[outer], inner - outer)
                  != (size_t) (inner - outer))
                {
-                 printf ("%s flunked bounded for outer = %d, inner = %d\n",
+                 printf ("%s flunked bounded for outer = %zu, inner = %zu\n",
                          STRINGIFY (STRNLEN), outer, inner);
                  result = 1;
                }
            }
+         if (outer == 0)
+           break;
        }
 
       /* strchr/wcschr test */
-      for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer)
+      for (outer = nchars - 1; outer >= max128; --outer)
        {
-         for (middle = MAX (outer, nchars - 64); middle < nchars; ++middle)
+         for (middle = MAX (outer, nchars64); middle < nchars; ++middle)
            {
              for (inner = middle; inner < nchars; ++inner)
                {
@@ -158,8 +174,8 @@ do_test (void)
                      || (inner != middle
                          && (cp - &adr[outer]) != middle - outer))
                    {
-                     printf ("%s flunked for outer = %d, middle = %d, "
-                             "inner = %d\n",
+                     printf ("%s flunked for outer = %zu, middle = %zu, "
+                             "inner = %zu\n",
                              STRINGIFY (STRCHR), outer, middle, inner);
                      result = 1;
                    }
@@ -168,6 +184,8 @@ do_test (void)
                  adr[middle] = L('T');
                }
            }
+         if (outer == 0)
+           break;
        }
 
       /* Special test.  */
@@ -180,9 +198,9 @@ do_test (void)
        }
 
       /* strrchr/wcsrchr test */
-      for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer)
+      for (outer = nchars - 1; outer >= max128; --outer)
        {
-         for (middle = MAX (outer, nchars - 64); middle < nchars; ++middle)
+         for (middle = MAX (outer, nchars64); middle < nchars; ++middle)
            {
              for (inner = middle; inner < nchars; ++inner)
                {
@@ -195,8 +213,8 @@ do_test (void)
                      || (inner != middle
                          && (cp - &adr[outer]) != middle - outer))
                    {
-                     printf ("%s flunked for outer = %d, middle = %d, "
-                             "inner = %d\n",
+                     printf ("%s flunked for outer = %zu, middle = %zu, "
+                             "inner = %zu\n",
                              STRINGIFY (STRRCHR), outer, middle, inner);
                      result = 1;
                    }
@@ -205,12 +223,14 @@ do_test (void)
                  adr[middle] = L('T');
                }
            }
+         if (outer == 0)
+           break;
        }
 
       /* memchr test */
-      for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer)
+      for (outer = nchars - 1; outer >= max128; --outer)
        {
-         for (middle = MAX (outer, nchars - 64); middle < nchars; ++middle)
+         for (middle = MAX (outer, nchars64); middle < nchars; ++middle)
            {
              adr[middle] = L('V');
 
@@ -218,32 +238,36 @@ do_test (void)
 
              if (cp - &adr[outer] != middle - outer)
                {
-                 printf ("%s flunked for outer = %d, middle = %d\n",
+                 printf ("%s flunked for outer = %zu, middle = %zu\n",
                          STRINGIFY (MEMCHR), outer, middle);
                  result = 1;
                }
 
              adr[middle] = L('T');
            }
+         if (outer == 0)
+           break;
        }
-      for (outer = nchars; outer >= MAX (0, nchars - 128); --outer)
+      for (outer = nchars; outer >= max128; --outer)
        {
          CHAR *cp = MEMCHR (&adr[outer], L('V'), nchars - outer);
 
          if (cp != NULL)
            {
-             printf ("%s flunked for outer = %d\n",
+             printf ("%s flunked for outer = %zu\n",
                      STRINGIFY (MEMCHR), outer);
              result = 1;
            }
+         if (outer == 0)
+           break;
        }
 
       /* These functions only exist for single-byte characters.  */
 #ifndef WCSTEST
       /* rawmemchr test */
-      for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer)
+      for (outer = nchars - 1; outer >= max128; --outer)
        {
-         for (middle = MAX (outer, nchars - 64); middle < nchars; ++middle)
+         for (middle = MAX (outer, nchars64); middle < nchars; ++middle)
            {
              adr[middle] = L('V');
 
@@ -251,19 +275,21 @@ do_test (void)
 
              if (cp - &adr[outer] != middle - outer)
                {
-                 printf ("%s flunked for outer = %d, middle = %d\n",
+                 printf ("%s flunked for outer = %zu, middle = %zu\n",
                          STRINGIFY (rawmemchr), outer, middle);
                  result = 1;
                }
 
              adr[middle] = L('T');
            }
+         if (outer == 0)
+           break;
        }
 
       /* memrchr test */
-      for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer)
+      for (outer = nchars - 1; outer >= max128; --outer)
        {
-         for (middle = MAX (outer, nchars - 64); middle < nchars; ++middle)
+         for (middle = MAX (outer, nchars64); middle < nchars; ++middle)
            {
              adr[middle] = L('V');
 
@@ -271,44 +297,50 @@ do_test (void)
 
              if (cp - &adr[outer] != middle - outer)
                {
-                 printf ("%s flunked for outer = %d, middle = %d\n",
+                 printf ("%s flunked for outer = %zu, middle = %zu\n",
                          STRINGIFY (memrchr), outer, middle);
                  result = 1;
                }
 
              adr[middle] = L('T');
            }
+         if (outer == 0)
+           break;
        }
-      for (outer = nchars; outer >= MAX (0, nchars - 128); --outer)
+      for (outer = nchars; outer >= max128; --outer)
        {
          CHAR *cp = memrchr (&adr[outer], L('V'), nchars - outer);
 
          if (cp != NULL)
            {
-             printf ("%s flunked for outer = %d\n",
+             printf ("%s flunked for outer = %zu\n",
                      STRINGIFY (memrchr), outer);
              result = 1;
            }
+         if (outer == 0)
+           break;
        }
 #endif
 
       /* strcpy/wcscpy test */
-      for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer)
+      for (outer = nchars - 1; outer >= max128; --outer)
        {
-         for (inner = MAX (outer, nchars - 64); inner < nchars; ++inner)
+         for (inner = MAX (outer, nchars64); inner < nchars; ++inner)
            {
              adr[inner] = L('\0');
 
              if (STRCPY (dest, &adr[outer]) != dest
                  || STRLEN (dest) != (size_t) (inner - outer))
                {
-                 printf ("%s flunked for outer = %d, inner = %d\n",
+                 printf ("%s flunked for outer = %zu, inner = %zu\n",
                          STRINGIFY (STRCPY), outer, inner);
                  result = 1;
                }
 
              adr[inner] = L('T');
            }
+         if (outer == 0)
+           break;
        }
 
       /* strcmp/wcscmp tests */
@@ -322,14 +354,14 @@ do_test (void)
 
            if (STRCMP (adr + middle, dest + nchars - outer) <= 0)
              {
-               printf ("%s 1 flunked for outer = %d, middle = %d\n",
+               printf ("%s 1 flunked for outer = %zu, middle = %zu\n",
                        STRINGIFY (STRCMP), outer, middle);
                result = 1;
              }
 
            if (STRCMP (dest + nchars - outer, adr + middle) >= 0)
              {
-               printf ("%s 2 flunked for outer = %d, middle = %d\n",
+               printf ("%s 2 flunked for outer = %zu, middle = %zu\n",
                        STRINGIFY (STRCMP), outer, middle);
                result = 1;
              }
@@ -348,16 +380,16 @@ do_test (void)
              {
                if (STRNCMP (adr + middle, dest + nchars - outer, inner) != 0)
                  {
-                   printf ("%s 1 flunked for outer = %d, middle = %d, "
-                           "inner = %d\n",
+                   printf ("%s 1 flunked for outer = %zu, middle = %zu, "
+                           "inner = %zu\n",
                            STRINGIFY (STRNCMP), outer, middle, inner);
                    result = 1;
                  }
 
                if (STRNCMP (dest + nchars - outer, adr + middle, inner) != 0)
                  {
-                   printf ("%s 2 flunked for outer = %d, middle = %d, "
-                           "inner = %d\n",
+                   printf ("%s 2 flunked for outer = %zu, middle = %zu, "
+                           "inner = %zu\n",
                            STRINGIFY (STRNCMP), outer, middle, inner);
                    result = 1;
                  }
@@ -365,14 +397,14 @@ do_test (void)
 
            if (STRNCMP (adr + middle, dest + nchars - outer, outer) >= 0)
              {
-               printf ("%s 1 flunked for outer = %d, middle = %d, full\n",
+               printf ("%s 1 flunked for outer = %zu, middle = %zu, full\n",
                        STRINGIFY (STRNCMP), outer, middle);
                result = 1;
              }
 
            if (STRNCMP (dest + nchars - outer, adr + middle, outer) <= 0)
              {
-               printf ("%s 2 flunked for outer = %d, middle = %d, full\n",
+               printf ("%s 2 flunked for outer = %zu, middle = %zu, full\n",
                        STRINGIFY (STRNCMP), outer, middle);
                result = 1;
              }
@@ -380,7 +412,7 @@ do_test (void)
 
       /* strncpy/wcsncpy tests */
       adr[nchars - 1] = L('T');
-      for (outer = nchars; outer >= MAX (0, nchars - 128); --outer)
+      for (outer = nchars; outer >= max128; --outer)
        {
          size_t len;
 
@@ -389,17 +421,19 @@ do_test (void)
              if (STRNCPY (dest, &adr[outer], len) != dest
                  || MEMCMP (dest, &adr[outer], len) != 0)
                {
-                 printf ("outer %s flunked for outer = %d, len = %Zd\n",
+                 printf ("outer %s flunked for outer = %zu, len = %zu\n",
                          STRINGIFY (STRNCPY), outer, len);
                  result = 1;
                }
            }
+         if (outer == 0)
+           break;
        }
       adr[nchars - 1] = L('\0');
 
-      for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer)
+      for (outer = nchars - 1; outer >= max128; --outer)
        {
-         for (inner = MAX (outer, nchars - 64); inner < nchars; ++inner)
+         for (inner = MAX (outer, nchars64); inner < nchars; ++inner)
            {
              size_t len;
 
@@ -413,8 +447,8 @@ do_test (void)
                      || (inner - outer < len
                          && STRLEN (dest) != (inner - outer)))
                    {
-                     printf ("%s flunked for outer = %d, inner = %d, "
-                             "len = %Zd\n",
+                     printf ("%s flunked for outer = %zu, inner = %zu, "
+                             "len = %zu\n",
                              STRINGIFY (STRNCPY), outer, inner, len);
                      result = 1;
                    }
@@ -424,8 +458,8 @@ do_test (void)
                      || (inner - outer < len
                          && STRLEN (dest + 1) != (inner - outer)))
                    {
-                     printf ("%s+1 flunked for outer = %d, inner = %d, "
-                             "len = %Zd\n",
+                     printf ("%s+1 flunked for outer = %zu, inner = %zu, "
+                             "len = %zu\n",
                              STRINGIFY (STRNCPY), outer, inner, len);
                      result = 1;
                    }
@@ -433,29 +467,33 @@ do_test (void)
 
              adr[inner] = L('T');
            }
+         if (outer == 0)
+           break;
        }
 
       /* stpcpy/wcpcpy test */
-      for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer)
+      for (outer = nchars - 1; outer >= max128; --outer)
        {
-         for (inner = MAX (outer, nchars - 64); inner < nchars; ++inner)
+         for (inner = MAX (outer, nchars64); inner < nchars; ++inner)
            {
              adr[inner] = L('\0');
 
              if ((STPCPY (dest, &adr[outer]) - dest) != inner - outer)
                {
-                 printf ("%s flunked for outer = %d, inner = %d\n",
+                 printf ("%s flunked for outer = %zu, inner = %zu\n",
                          STRINGIFY (STPCPY), outer, inner);
                  result = 1;
                }
 
              adr[inner] = L('T');
            }
+         if (outer == 0)
+           break;
        }
 
       /* stpncpy/wcpncpy test */
       adr[nchars - 1] = L('T');
-      for (outer = nchars; outer >= MAX (0, nchars - 128); --outer)
+      for (outer = nchars; outer >= max128; --outer)
        {
          size_t len;
 
@@ -464,17 +502,19 @@ do_test (void)
              if (STPNCPY (dest, &adr[outer], len) != dest + len
                  || MEMCMP (dest, &adr[outer], len) != 0)
                {
-                 printf ("outer %s flunked for outer = %d, len = %Zd\n",
+                 printf ("outer %s flunked for outer = %zu, len = %zu\n",
                          STRINGIFY (STPNCPY), outer, len);
                  result = 1;
                }
            }
+         if (outer == 0)
+           break;
        }
       adr[nchars - 1] = L('\0');
 
-      for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer)
+      for (outer = nchars - 1; outer >= max128; --outer)
        {
-         for (middle = MAX (outer, nchars - 64); middle < nchars; ++middle)
+         for (middle = MAX (outer, nchars64); middle < nchars; ++middle)
            {
              adr[middle] = L('\0');
 
@@ -483,8 +523,8 @@ do_test (void)
                  if ((STPNCPY (dest, &adr[outer], inner) - dest)
                      != MIN (inner, middle - outer))
                    {
-                     printf ("%s flunked for outer = %d, middle = %d, "
-                             "inner = %d\n",
+                     printf ("%s flunked for outer = %zu, middle = %zu, "
+                             "inner = %zu\n",
                              STRINGIFY (STPNCPY), outer, middle, inner);
                      result = 1;
                    }
@@ -492,66 +532,84 @@ do_test (void)
 
              adr[middle] = L('T');
            }
+         if (outer == 0)
+           break;
        }
 
       /* memcpy/wmemcpy test */
-      for (outer = nchars; outer >= MAX (0, nchars - 128); --outer)
-       for (inner = 0; inner < nchars - outer; ++inner)
-         if (MEMCPY (dest, &adr[outer], inner) !=  dest)
-           {
-             printf ("%s flunked for outer = %d, inner = %d\n",
-                     STRINGIFY (MEMCPY), outer, inner);
-             result = 1;
-           }
+      for (outer = nchars; outer >= max128; --outer)
+       {
+         for (inner = 0; inner < nchars - outer; ++inner)
+           if (MEMCPY (dest, &adr[outer], inner) !=  dest)
+             {
+               printf ("%s flunked for outer = %zu, inner = %zu\n",
+                       STRINGIFY (MEMCPY), outer, inner);
+               result = 1;
+             }
+         if (outer == 0)
+           break;
+       }
 
       /* mempcpy/wmempcpy test */
-      for (outer = nchars; outer >= MAX (0, nchars - 128); --outer)
-       for (inner = 0; inner < nchars - outer; ++inner)
-         if (MEMPCPY (dest, &adr[outer], inner) !=  dest + inner)
-           {
-             printf ("%s flunked for outer = %d, inner = %d\n",
-                     STRINGIFY (MEMPCPY), outer, inner);
-             result = 1;
-           }
+      for (outer = nchars; outer >= max128; --outer)
+       {
+         for (inner = 0; inner < nchars - outer; ++inner)
+           if (MEMPCPY (dest, &adr[outer], inner) !=  dest + inner)
+             {
+               printf ("%s flunked for outer = %zu, inner = %zu\n",
+                       STRINGIFY (MEMPCPY), outer, inner);
+               result = 1;
+             }
+         if (outer == 0)
+           break;
+       }
 
       /* This function only exists for single-byte characters.  */
 #ifndef WCSTEST
       /* memccpy test */
       memset (adr, '\0', nchars);
-      for (outer = nchars; outer >= MAX (0, nchars - 128); --outer)
-       for (inner = 0; inner < nchars - outer; ++inner)
-         if (memccpy (dest, &adr[outer], L('\1'), inner) != NULL)
-           {
-             printf ("memccpy flunked full copy for outer = %d, inner = %d\n",
-                     outer, inner);
-             result = 1;
-           }
-      for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer)
-       for (middle = 0; middle < nchars - outer; ++middle)
-         {
-           memset (dest, L('\2'), middle + 1);
-           for (inner = 0; inner < middle; ++inner)
+      for (outer = nchars; outer >= max128; --outer)
+       {
+         for (inner = 0; inner < nchars - outer; ++inner)
+           if (memccpy (dest, &adr[outer], L('\1'), inner) != NULL)
              {
-               adr[outer + inner] = L('\1');
-
-               if (memccpy (dest, &adr[outer], '\1', middle + 128)
-                   !=  dest + inner + 1)
-                 {
-                   printf ("\
-memccpy flunked partial copy for outer = %d, middle = %d, inner = %d\n",
-                           outer, middle, inner);
-                   result = 1;
-                 }
-               else if (dest[inner + 1] != L('\2'))
-                 {
-                   printf ("\
-memccpy copied too much for outer = %d, middle = %d, inner = %d\n",
-                           outer, middle, inner);
-                   result = 1;
-                 }
-               adr[outer + inner] = L('\0');
+               printf ("memccpy flunked full copy for outer = %zu, inner = %zu\n",
+                       outer, inner);
+               result = 1;
              }
-         }
+         if (outer == 0)
+           break;
+       }
+      for (outer = nchars - 1; outer >= max128; --outer)
+       {
+         for (middle = 0; middle < nchars - outer; ++middle)
+           {
+             memset (dest, L('\2'), middle + 1);
+             for (inner = 0; inner < middle; ++inner)
+               {
+                 adr[outer + inner] = L('\1');
+
+                 if (memccpy (dest, &adr[outer], '\1', middle + 128)
+                     !=  dest + inner + 1)
+                   {
+                     printf ("\
+                             memccpy flunked partial copy for outer = %zu, middle = %zu, inner = %zu\n",
+                             outer, middle, inner);
+                     result = 1;
+                   }
+                 else if (dest[inner + 1] != L('\2'))
+                   {
+                     printf ("\
+                             memccpy copied too much for outer = %zu, middle = %zu, inner = %zu\n",
+                             outer, middle, inner);
+                     result = 1;
+                   }
+                 adr[outer + inner] = L('\0');
+               }
+           }
+         if (outer == 0)
+           break;
+       }
 #endif
     }
 
index d62889ff8fb672f2909d3973f7417ce06a2cdeba..6431605c7eeb6c48ca7068032640d7ff08f2ea2e 100644 (file)
@@ -208,6 +208,12 @@ test_main (void)
       do_test (0, i, i + 1, i + 1, 0);
     }
 
+  /* BZ#21182 - wrong overflow calculation for i686 implementation
+     with address near end of the page.  */
+  for (i = 2; i < 16; ++i)
+    /* page_size is in fact getpagesize() * 2.  */
+    do_test (page_size / 2 - i, i, i, 1, 0x9B);
+
   do_random_tests ();
   return ret;
 }
index 0c1e6124ff4bf93ca4a2fca579d50fde298d18d4..7e5d2955a0f4afa06683245954a53adf1dd0edd5 100644 (file)
@@ -93,11 +93,12 @@ rpcgen-objs = rpc_main.o rpc_hout.o rpc_cout.o rpc_parse.o \
 extra-objs = $(rpcgen-objs) $(addprefix cross-,$(rpcgen-objs))
 others += rpcgen
 
-tests = tst-xdrmem tst-xdrmem2 test-rpcent
+tests = tst-xdrmem tst-xdrmem2 test-rpcent tst-udp-error tst-udp-timeout \
+  tst-udp-nonblocking
 xtests := tst-getmyaddr
 
 ifeq ($(have-thread-library),yes)
-xtests += thrsvc
+xtests += thrsvc tst-udp-garbage
 endif
 
 ifeq ($(run-built-tests),yes)
@@ -155,6 +156,7 @@ BUILD_CPPFLAGS += $(sunrpc-CPPFLAGS)
 $(objpfx)tst-getmyaddr: $(common-objpfx)linkobj/libc.so
 $(objpfx)tst-xdrmem: $(common-objpfx)linkobj/libc.so
 $(objpfx)tst-xdrmem2: $(common-objpfx)linkobj/libc.so
+$(objpfx)tst-udp-error: $(common-objpfx)linkobj/libc.so
 
 $(objpfx)rpcgen: $(addprefix $(objpfx),$(rpcgen-objs))
 
@@ -234,3 +236,8 @@ $(rpcgen-tests): $(objpfx)%.out: %.x $(objpfx)rpcgen
        $(built-program-cmd) -c $< -o $@; \
        $(evaluate-test)
 endif
+
+$(objpfx)tst-udp-timeout: $(common-objpfx)linkobj/libc.so
+$(objpfx)tst-udp-nonblocking: $(common-objpfx)linkobj/libc.so
+$(objpfx)tst-udp-garbage: \
+  $(common-objpfx)linkobj/libc.so $(shared-thread-library)
index 4d9acb1e6a6bbad9440a87b59a3e8c1fb92a7b4e..6ce16eb2988c64b5178d0ce6a1cc28271774e023 100644 (file)
@@ -55,6 +55,7 @@
 #endif
 
 #include <kernel-features.h>
+#include <inet/net-internal.h>
 
 extern u_long _create_xid (void);
 
@@ -80,7 +81,9 @@ static const struct clnt_ops udp_ops =
 };
 
 /*
- * Private data kept per client handle
+ * Private data kept per client handle.  This private struct is
+ * unfortunately part of the ABI; ypbind contains a copy of it and
+ * accesses it through CLIENT::cl_private field.
  */
 struct cu_data
   {
@@ -278,28 +281,38 @@ clntudp_call (/* client handle */
   int inlen;
   socklen_t fromlen;
   struct pollfd fd;
-  int milliseconds = (cu->cu_wait.tv_sec * 1000) +
-    (cu->cu_wait.tv_usec / 1000);
   struct sockaddr_in from;
   struct rpc_msg reply_msg;
   XDR reply_xdrs;
-  struct timeval time_waited;
   bool_t ok;
   int nrefreshes = 2;          /* number of times to refresh cred */
-  struct timeval timeout;
   int anyup;                   /* any network interface up */
 
-  if (cu->cu_total.tv_usec == -1)
-    {
-      timeout = utimeout;      /* use supplied timeout */
-    }
-  else
+  struct deadline_current_time current_time = __deadline_current_time ();
+  struct deadline total_deadline; /* Determined once by overall timeout.  */
+  struct deadline response_deadline; /* Determined anew for each query.  */
+
+  /* Choose the timeout value.  For non-sending usage (xargs == NULL),
+     the total deadline does not matter, only cu->cu_wait is used
+     below.  */
+  if (xargs != NULL)
     {
-      timeout = cu->cu_total;  /* use default timeout */
+      struct timeval tv;
+      if (cu->cu_total.tv_usec == -1)
+       /* Use supplied timeout.  */
+       tv = utimeout;
+      else
+       /* Use default timeout.  */
+       tv = cu->cu_total;
+      if (!__is_timeval_valid_timeout (tv))
+       return (cu->cu_error.re_status = RPC_TIMEDOUT);
+      total_deadline = __deadline_from_timeval (current_time, tv);
     }
 
-  time_waited.tv_sec = 0;
-  time_waited.tv_usec = 0;
+  /* Guard against bad timeout specification.  */
+  if (!__is_timeval_valid_timeout (cu->cu_wait))
+    return (cu->cu_error.re_status = RPC_TIMEDOUT);
+
 call_again:
   xdrs = &(cu->cu_outxdrs);
   if (xargs == NULL)
@@ -325,27 +338,46 @@ send_again:
       return (cu->cu_error.re_status = RPC_CANTSEND);
     }
 
-  /*
-   * Hack to provide rpc-based message passing
-   */
-  if (timeout.tv_sec == 0 && timeout.tv_usec == 0)
-    {
-      return (cu->cu_error.re_status = RPC_TIMEDOUT);
-    }
+  /* sendto may have blocked, so recompute the current time.  */
+  current_time = __deadline_current_time ();
  get_reply:
-  /*
-   * sub-optimal code appears here because we have
-   * some clock time to spare while the packets are in flight.
-   * (We assume that this is actually only executed once.)
-   */
+  response_deadline = __deadline_from_timeval (current_time, cu->cu_wait);
+
   reply_msg.acpted_rply.ar_verf = _null_auth;
   reply_msg.acpted_rply.ar_results.where = resultsp;
   reply_msg.acpted_rply.ar_results.proc = xresults;
   fd.fd = cu->cu_sock;
   fd.events = POLLIN;
   anyup = 0;
+
+  /* Per-response retry loop.  current_time must be up-to-date at the
+     top of the loop.  */
   for (;;)
     {
+      int milliseconds;
+      if (xargs != NULL)
+       {
+         if (__deadline_elapsed (current_time, total_deadline))
+           /* Overall timeout expired.  */
+           return (cu->cu_error.re_status = RPC_TIMEDOUT);
+         milliseconds = __deadline_to_ms
+           (current_time, __deadline_first (total_deadline,
+                                            response_deadline));
+         if (milliseconds == 0)
+           /* Per-query timeout expired.  */
+           goto send_again;
+       }
+      else
+       {
+         /* xatgs == NULL.  Collect a response without sending a
+            query.  In this mode, we need to ignore the total
+            deadline.  */
+         milliseconds = __deadline_to_ms (current_time, response_deadline);
+         if (milliseconds == 0)
+           /* Cannot send again, so bail out.  */
+           return (cu->cu_error.re_status = RPC_CANTSEND);
+       }
+
       switch (__poll (&fd, 1, milliseconds))
        {
 
@@ -356,27 +388,10 @@ send_again:
              if (!anyup)
                return (cu->cu_error.re_status = RPC_CANTRECV);
            }
-
-         time_waited.tv_sec += cu->cu_wait.tv_sec;
-         time_waited.tv_usec += cu->cu_wait.tv_usec;
-         while (time_waited.tv_usec >= 1000000)
-           {
-             time_waited.tv_sec++;
-             time_waited.tv_usec -= 1000000;
-           }
-         if ((time_waited.tv_sec < timeout.tv_sec) ||
-             ((time_waited.tv_sec == timeout.tv_sec) &&
-              (time_waited.tv_usec < timeout.tv_usec)))
-           goto send_again;
-         return (cu->cu_error.re_status = RPC_TIMEDOUT);
-
-         /*
-          * buggy in other cases because time_waited is not being
-          * updated.
-          */
+         goto next_response;
        case -1:
          if (errno == EINTR)
-           continue;
+           goto next_response;
          cu->cu_error.re_errno = errno;
          return (cu->cu_error.re_status = RPC_CANTRECV);
        }
@@ -421,9 +436,9 @@ send_again:
                 cmsg = CMSG_NXTHDR (&msg, cmsg))
              if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR)
                {
-                 free (cbuf);
                  e = (struct sock_extended_err *) CMSG_DATA(cmsg);
                  cu->cu_error.re_errno = e->ee_errno;
+                 free (cbuf);
                  return (cu->cu_error.re_status = RPC_CANTRECV);
                }
          free (cbuf);
@@ -440,20 +455,22 @@ send_again:
       if (inlen < 0)
        {
          if (errno == EWOULDBLOCK)
-           continue;
+           goto next_response;
          cu->cu_error.re_errno = errno;
          return (cu->cu_error.re_status = RPC_CANTRECV);
        }
-      if (inlen < 4)
-       continue;
-
-      /* see if reply transaction id matches sent id.
-       Don't do this if we only wait for a replay */
-      if (xargs != NULL
-         && memcmp (cu->cu_inbuf, cu->cu_outbuf, sizeof (u_int32_t)) != 0)
-       continue;
-      /* we now assume we have the proper reply */
-      break;
+      /* Accept the response if the packet is sufficiently long and
+        the transaction ID matches the query (if available).  */
+      if (inlen >= 4
+         && (xargs == NULL
+             || memcmp (cu->cu_inbuf, cu->cu_outbuf,
+                        sizeof (u_int32_t)) == 0))
+       break;
+
+    next_response:
+      /* Update the current time because poll and recvmsg waited for
+        an unknown time.  */
+      current_time = __deadline_current_time ();
     }
 
   /*
diff --git a/sunrpc/tst-udp-error.c b/sunrpc/tst-udp-error.c
new file mode 100644 (file)
index 0000000..1efc02f
--- /dev/null
@@ -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
+   <http://www.gnu.org/licenses/>.  */
+
+#include <netinet/in.h>
+#include <rpc/clnt.h>
+#include <rpc/svc.h>
+#include <support/check.h>
+#include <support/namespace.h>
+#include <support/xsocket.h>
+#include <unistd.h>
+
+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 <support/test-driver.c>
diff --git a/sunrpc/tst-udp-garbage.c b/sunrpc/tst-udp-garbage.c
new file mode 100644 (file)
index 0000000..4abda93
--- /dev/null
@@ -0,0 +1,104 @@
+/* Test that garbage packets do not affect timeout handling.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <netinet/in.h>
+#include <rpc/clnt.h>
+#include <rpc/svc.h>
+#include <stdbool.h>
+#include <support/check.h>
+#include <support/namespace.h>
+#include <support/xsocket.h>
+#include <support/xthread.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+/* Descriptor for the server UDP socket.  */
+static int server_fd;
+
+static void *
+garbage_sender_thread (void *unused)
+{
+  while (true)
+    {
+      struct sockaddr_storage sa;
+      socklen_t salen = sizeof (sa);
+      char buf[1];
+      if (recvfrom (server_fd, buf, sizeof (buf), 0,
+                    (struct sockaddr *) &sa, &salen) < 0)
+        FAIL_EXIT1 ("recvfrom: %m");
+
+      /* Send garbage packets indefinitely.  */
+      buf[0] = 0;
+      while (true)
+        {
+          /* sendto can fail if the client closed the socket.  */
+          if (sendto (server_fd, buf, sizeof (buf), 0,
+                      (struct sockaddr *) &sa, salen) < 0)
+            break;
+
+          /* Wait a bit, to avoid burning too many CPU cycles in a
+             tight loop.  The wait period must be much shorter than
+             the client timeouts configured below.  */
+          usleep (50 * 1000);
+        }
+    }
+}
+
+static int
+do_test (void)
+{
+  support_become_root ();
+  support_enter_network_namespace ();
+
+  server_fd = xsocket (AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP);
+  struct sockaddr_in server_address =
+    {
+      .sin_family = AF_INET,
+      .sin_addr.s_addr = htonl (INADDR_LOOPBACK),
+    };
+  xbind (server_fd,
+         (struct sockaddr *) &server_address, sizeof (server_address));
+  {
+    socklen_t sinlen = sizeof (server_address);
+    xgetsockname (server_fd, (struct sockaddr *) &server_address, &sinlen);
+    TEST_VERIFY (sizeof (server_address) == sinlen);
+  }
+
+  /* Garbage packet source.  */
+  xpthread_detach (xpthread_create (NULL, garbage_sender_thread, NULL));
+
+  /* Test client.  Use an arbitrary timeout of one second, which is
+     much longer than the garbage packet interval, but still
+     reasonably short, so that the test completes quickly.  */
+  int client_fd = RPC_ANYSOCK;
+  CLIENT *clnt = clntudp_create (&server_address,
+                                 1, 2, /* Arbitrary RPC endpoint numbers.  */
+                                 (struct timeval) { 1, 0 },
+                                 &client_fd);
+  if (clnt == NULL)
+    FAIL_EXIT1 ("clntudp_create: %m");
+
+  TEST_VERIFY (clnt_call (clnt, 3, /* Arbitrary RPC procedure number.  */
+                          (xdrproc_t) xdr_void, NULL,
+                          (xdrproc_t) xdr_void, NULL,
+                          ((struct timeval) { 1, 0 })));
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sunrpc/tst-udp-nonblocking.c b/sunrpc/tst-udp-nonblocking.c
new file mode 100644 (file)
index 0000000..1d6a7f4
--- /dev/null
@@ -0,0 +1,333 @@
+/* Test non-blocking use of the UDP client.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <netinet/in.h>
+#include <rpc/clnt.h>
+#include <rpc/svc.h>
+#include <stdbool.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/namespace.h>
+#include <support/test-driver.h>
+#include <support/xsocket.h>
+#include <support/xunistd.h>
+#include <sys/socket.h>
+#include <time.h>
+#include <unistd.h>
+
+/* Test data serialization and deserialization.   */
+
+struct test_query
+{
+  uint32_t a;
+  uint32_t b;
+  uint32_t timeout_ms;
+};
+
+static bool_t
+xdr_test_query (XDR *xdrs, void *data, ...)
+{
+  struct test_query *p = data;
+  return xdr_uint32_t (xdrs, &p->a)
+    && xdr_uint32_t (xdrs, &p->b)
+    && xdr_uint32_t (xdrs, &p->timeout_ms);
+}
+
+struct test_response
+{
+  uint32_t server_id;
+  uint32_t seq;
+  uint32_t sum;
+};
+
+static bool_t
+xdr_test_response (XDR *xdrs, void *data, ...)
+{
+  struct test_response *p = data;
+  return xdr_uint32_t (xdrs, &p->server_id)
+    && xdr_uint32_t (xdrs, &p->seq)
+    && xdr_uint32_t (xdrs, &p->sum);
+}
+
+/* Implementation of the test server.  */
+
+enum
+  {
+    /* Number of test servers to run. */
+    SERVER_COUNT = 3,
+
+    /* RPC parameters, chosen at random.  */
+    PROGNUM = 8242,
+    VERSNUM = 19654,
+
+    /* Main RPC operation.  */
+    PROC_ADD = 1,
+
+    /* Request process termination.  */
+    PROC_EXIT,
+
+    /* Special exit status to mark successful processing.  */
+    EXIT_MARKER = 55,
+  };
+
+/* Set by the parent process to tell test servers apart.  */
+static int server_id;
+
+/* Implementation of the test server.  */
+static void
+server_dispatch (struct svc_req *request, SVCXPRT *transport)
+{
+  /* Query sequence number.  */
+  static uint32_t seq = 0;
+  ++seq;
+  static bool proc_add_seen;
+
+  if (test_verbose)
+    printf ("info: server_dispatch server_id=%d seq=%u rq_proc=%lu\n",
+            server_id, seq, request->rq_proc);
+
+  switch (request->rq_proc)
+    {
+    case PROC_ADD:
+      {
+        struct test_query query;
+        memset (&query, 0xc0, sizeof (query));
+        TEST_VERIFY_EXIT
+          (svc_getargs (transport, xdr_test_query,
+                        (void *) &query));
+
+        if (test_verbose)
+          printf ("  a=%u b=%u timeout_ms=%u\n",
+                  query.a, query.b, query.timeout_ms);
+
+        usleep (query.timeout_ms * 1000);
+
+        struct test_response response =
+          {
+            .server_id = server_id,
+            .seq = seq,
+            .sum = query.a + query.b,
+          };
+        TEST_VERIFY (svc_sendreply (transport, xdr_test_response,
+                                    (void *) &response));
+        if (test_verbose)
+          printf ("  server id %d response seq=%u sent\n", server_id, seq);
+        proc_add_seen = true;
+      }
+      break;
+
+    case PROC_EXIT:
+      TEST_VERIFY (proc_add_seen);
+      TEST_VERIFY (svc_sendreply (transport, (xdrproc_t) xdr_void, NULL));
+      _exit (EXIT_MARKER);
+      break;
+
+    default:
+      FAIL_EXIT1 ("invalid rq_proc value: %lu", request->rq_proc);
+      break;
+    }
+}
+
+/* Return the number seconds since an arbitrary point in time.  */
+static double
+get_ticks (void)
+{
+  {
+    struct timespec ts;
+    if (clock_gettime (CLOCK_MONOTONIC, &ts) == 0)
+      return ts.tv_sec + ts.tv_nsec * 1e-9;
+  }
+  {
+    struct timeval tv;
+    TEST_VERIFY_EXIT (gettimeofday (&tv, NULL) == 0);
+    return tv.tv_sec + tv.tv_usec * 1e-6;
+  }
+}
+
+static int
+do_test (void)
+{
+  support_become_root ();
+  support_enter_network_namespace ();
+
+  /* Information about the test servers.  */
+  struct
+  {
+    SVCXPRT *transport;
+    struct sockaddr_in address;
+    pid_t pid;
+    uint32_t xid;
+  } servers[SERVER_COUNT];
+
+  /* Spawn the test servers.  */
+  for (int i = 0; i < SERVER_COUNT; ++i)
+    {
+      servers[i].transport = svcudp_create (RPC_ANYSOCK);
+      TEST_VERIFY_EXIT (servers[i].transport != NULL);
+      servers[i].address = (struct sockaddr_in)
+        {
+          .sin_family = AF_INET,
+          .sin_addr.s_addr = htonl (INADDR_LOOPBACK),
+          .sin_port = htons (servers[i].transport->xp_port),
+        };
+      servers[i].xid = 0xabcd0101 + i;
+      if (test_verbose)
+        printf ("info: setting up server %d xid=%x on port %d\n",
+                i, servers[i].xid, servers[i].transport->xp_port);
+
+      server_id = i;
+      servers[i].pid = xfork ();
+      if (servers[i].pid == 0)
+        {
+          TEST_VERIFY (svc_register (servers[i].transport,
+                                     PROGNUM, VERSNUM, server_dispatch, 0));
+          svc_run ();
+          FAIL_EXIT1 ("supposed to be unreachable");
+        }
+      /* We need to close the socket so that we do not accidentally
+         consume the request.  */
+      TEST_VERIFY (close (servers[i].transport->xp_sock) == 0);
+    }
+
+
+  /* The following code mirrors what ypbind does.  */
+
+  /* Copied from clnt_udp.c (like ypbind).  */
+  struct cu_data
+  {
+    int cu_sock;
+    bool_t cu_closeit;
+    struct sockaddr_in cu_raddr;
+    int cu_rlen;
+    struct timeval cu_wait;
+    struct timeval cu_total;
+    struct rpc_err cu_error;
+    XDR cu_outxdrs;
+    u_int cu_xdrpos;
+    u_int cu_sendsz;
+    char *cu_outbuf;
+    u_int cu_recvsz;
+    char cu_inbuf[1];
+  };
+
+  int client_socket = xsocket (AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0);
+  CLIENT *clnt = clntudp_create (&servers[0].address, PROGNUM, VERSNUM,
+                                 /* 5 seconds per-response timeout.  */
+                                 ((struct timeval) { 5, 0 }),
+                                 &client_socket);
+  TEST_VERIFY (clnt != NULL);
+  clnt->cl_auth = authunix_create_default ();
+  {
+    struct timeval zero = { 0, 0 };
+    TEST_VERIFY (clnt_control (clnt, CLSET_TIMEOUT, (void *) &zero));
+  }
+
+  /* Poke at internal data structures (like ypbind).  */
+  struct cu_data *cu = (struct cu_data *) clnt->cl_private;
+
+  /* Send a ping to each server.  */
+  double before_pings = get_ticks ();
+  for (int i = 0; i < SERVER_COUNT; ++i)
+    {
+      if (test_verbose)
+        printf ("info: sending server %d ping\n", i);
+      /* Reset the xid because it is changed by each invocation of
+         clnt_call.  Subtract one to compensate for the xid update
+         during the call.  */
+      *((u_int32_t *) (cu->cu_outbuf)) = servers[i].xid - 1;
+      cu->cu_raddr = servers[i].address;
+
+      struct test_query query = { .a = 100, .b = i + 1 };
+      if (i == 1)
+        /* Shorter timeout to prefer this server.  These timeouts must
+           be much shorter than the 5-second per-response timeout
+           configured with clntudp_create.  */
+        query.timeout_ms = 700;
+      else
+        query.timeout_ms = 1400;
+      struct test_response response = { 0 };
+      /* NB: Do not check the return value.  The server reply will
+         prove that the call worked.  */
+      double before_one_ping = get_ticks ();
+      clnt_call (clnt, PROC_ADD,
+                 xdr_test_query, (void *) &query,
+                 xdr_test_response, (void *) &response,
+                 ((struct timeval) { 0, 0 }));
+      double after_one_ping = get_ticks ();
+      if (test_verbose)
+        printf ("info: non-blocking send took %f seconds\n",
+                after_one_ping - before_one_ping);
+      /* clnt_call should return immediately.  Accept some delay in
+         case the process is descheduled.  */
+      TEST_VERIFY (after_one_ping - before_one_ping < 0.3);
+    }
+
+  /* Collect the non-blocking response.  */
+  if (test_verbose)
+    printf ("info: collecting response\n");
+  struct test_response response = { 0 };
+  TEST_VERIFY
+    (clnt_call (clnt, PROC_ADD, NULL, NULL,
+                xdr_test_response, (void *) &response,
+                ((struct timeval) { 0, 0 })) == RPC_SUCCESS);
+  double after_pings = get_ticks ();
+  if (test_verbose)
+    printf ("info: send/receive took %f seconds\n",
+            after_pings - before_pings);
+  /* Expected timeout is 0.7 seconds.  */
+  TEST_VERIFY (0.7 <= after_pings - before_pings);
+  TEST_VERIFY (after_pings - before_pings < 1.2);
+
+  uint32_t xid;
+  memcpy (&xid, &cu->cu_inbuf, sizeof (xid));
+  if (test_verbose)
+    printf ("info: non-blocking response: xid=%x server_id=%u seq=%u sum=%u\n",
+            xid, response.server_id, response.seq, response.sum);
+  /* Check that the reply from the preferred server was used.  */
+  TEST_VERIFY (servers[1].xid == xid);
+  TEST_VERIFY (response.server_id == 1);
+  TEST_VERIFY (response.seq == 1);
+  TEST_VERIFY (response.sum == 102);
+
+  auth_destroy (clnt->cl_auth);
+  clnt_destroy (clnt);
+
+  for (int i = 0; i < SERVER_COUNT; ++i)
+    {
+      if (test_verbose)
+        printf ("info: requesting server %d termination\n", i);
+      client_socket = RPC_ANYSOCK;
+      clnt = clntudp_create (&servers[i].address, PROGNUM, VERSNUM,
+                             ((struct timeval) { 5, 0 }),
+                             &client_socket);
+      TEST_VERIFY_EXIT (clnt != NULL);
+      TEST_VERIFY (clnt_call (clnt, PROC_EXIT,
+                              (xdrproc_t) xdr_void, NULL,
+                              (xdrproc_t) xdr_void, NULL,
+                              ((struct timeval) { 3, 0 })) == RPC_SUCCESS);
+      clnt_destroy (clnt);
+
+      int status;
+      xwaitpid (servers[i].pid, &status, 0);
+      TEST_VERIFY (WIFEXITED (status) && WEXITSTATUS (status) == EXIT_MARKER);
+    }
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sunrpc/tst-udp-timeout.c b/sunrpc/tst-udp-timeout.c
new file mode 100644 (file)
index 0000000..db9943a
--- /dev/null
@@ -0,0 +1,402 @@
+/* Test timeout handling in the UDP client.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <netinet/in.h>
+#include <rpc/clnt.h>
+#include <rpc/svc.h>
+#include <stdbool.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/namespace.h>
+#include <support/test-driver.h>
+#include <support/xsocket.h>
+#include <support/xunistd.h>
+#include <sys/socket.h>
+#include <time.h>
+#include <unistd.h>
+
+/* Test data serialization and deserialization.   */
+
+struct test_query
+{
+  uint32_t a;
+  uint32_t b;
+  uint32_t timeout_ms;
+  uint32_t wait_for_seq;
+  uint32_t garbage_packets;
+};
+
+static bool_t
+xdr_test_query (XDR *xdrs, void *data, ...)
+{
+  struct test_query *p = data;
+  return xdr_uint32_t (xdrs, &p->a)
+    && xdr_uint32_t (xdrs, &p->b)
+    && xdr_uint32_t (xdrs, &p->timeout_ms)
+    && xdr_uint32_t (xdrs, &p->wait_for_seq)
+    && xdr_uint32_t (xdrs, &p->garbage_packets);
+}
+
+struct test_response
+{
+  uint32_t seq;
+  uint32_t sum;
+};
+
+static bool_t
+xdr_test_response (XDR *xdrs, void *data, ...)
+{
+  struct test_response *p = data;
+  return xdr_uint32_t (xdrs, &p->seq)
+    && xdr_uint32_t (xdrs, &p->sum);
+}
+
+/* Implementation of the test server.  */
+
+enum
+  {
+    /* RPC parameters, chosen at random.  */
+    PROGNUM = 15717,
+    VERSNUM = 13689,
+
+    /* Main RPC operation.  */
+    PROC_ADD = 1,
+
+    /* Reset the sequence number.  */
+    PROC_RESET_SEQ,
+
+    /* Request process termination.  */
+    PROC_EXIT,
+
+    /* Special exit status to mark successful processing.  */
+    EXIT_MARKER = 55,
+  };
+
+static void
+server_dispatch (struct svc_req *request, SVCXPRT *transport)
+{
+  /* Query sequence number.  */
+  static uint32_t seq = 0;
+  ++seq;
+
+  if (test_verbose)
+    printf ("info: server_dispatch seq=%u rq_proc=%lu\n",
+            seq, request->rq_proc);
+
+  switch (request->rq_proc)
+    {
+    case PROC_ADD:
+      {
+        struct test_query query;
+        memset (&query, 0xc0, sizeof (query));
+        TEST_VERIFY_EXIT
+          (svc_getargs (transport, xdr_test_query,
+                        (void *) &query));
+
+        if (test_verbose)
+          printf ("  a=%u b=%u timeout_ms=%u wait_for_seq=%u"
+                  " garbage_packets=%u\n",
+                  query.a, query.b, query.timeout_ms, query.wait_for_seq,
+                  query.garbage_packets);
+
+        if (seq < query.wait_for_seq)
+          {
+            /* No response at this point.  */
+            if (test_verbose)
+              printf ("  skipped response\n");
+            break;
+          }
+
+        if (query.garbage_packets > 0)
+          {
+            int per_packet_timeout;
+            if (query.timeout_ms > 0)
+              per_packet_timeout
+                = query.timeout_ms * 1000 / query.garbage_packets;
+            else
+              per_packet_timeout = 0;
+
+            char buf[20];
+            memset (&buf, 0xc0, sizeof (buf));
+            for (int i = 0; i < query.garbage_packets; ++i)
+              {
+                /* 13 is relatively prime to 20 = sizeof (buf) + 1, so
+                   the len variable will cover the entire interval
+                   [0, 20] if query.garbage_packets is sufficiently
+                   large.  */
+                size_t len = (i * 13 + 1) % (sizeof (buf) + 1);
+                TEST_VERIFY (sendto (transport->xp_sock,
+                                     buf, len, MSG_NOSIGNAL,
+                                     (struct sockaddr *) &transport->xp_raddr,
+                                     transport->xp_addrlen) == len);
+                if (per_packet_timeout > 0)
+                  usleep (per_packet_timeout);
+              }
+          }
+        else if (query.timeout_ms > 0)
+          usleep (query.timeout_ms * 1000);
+
+        struct test_response response =
+          {
+            .seq = seq,
+            .sum = query.a + query.b,
+          };
+        TEST_VERIFY (svc_sendreply (transport, xdr_test_response,
+                                    (void *) &response));
+      }
+      break;
+
+    case PROC_RESET_SEQ:
+      seq = 0;
+      TEST_VERIFY (svc_sendreply (transport, (xdrproc_t) xdr_void, NULL));
+      break;
+
+    case PROC_EXIT:
+      TEST_VERIFY (svc_sendreply (transport, (xdrproc_t) xdr_void, NULL));
+      _exit (EXIT_MARKER);
+      break;
+
+    default:
+      FAIL_EXIT1 ("invalid rq_proc value: %lu", request->rq_proc);
+      break;
+    }
+}
+
+/* Implementation of the test client.  */
+
+static struct test_response
+test_call (CLIENT *clnt, int proc, struct test_query query,
+           struct timeval timeout)
+{
+  if (test_verbose)
+    printf ("info: test_call proc=%d timeout=%lu.%06lu\n",
+            proc, (unsigned long) timeout.tv_sec,
+            (unsigned long) timeout.tv_usec);
+  struct test_response response;
+  TEST_VERIFY_EXIT (clnt_call (clnt, proc,
+                               xdr_test_query, (void *) &query,
+                               xdr_test_response, (void *) &response,
+                               timeout)
+                    == RPC_SUCCESS);
+  return response;
+}
+
+static void
+test_call_timeout (CLIENT *clnt, int proc, struct test_query query,
+                   struct timeval timeout)
+{
+  struct test_response response;
+  TEST_VERIFY (clnt_call (clnt, proc,
+                          xdr_test_query, (void *) &query,
+                          xdr_test_response, (void *) &response,
+                          timeout)
+               == RPC_TIMEDOUT);
+}
+
+/* Complete one regular RPC call to drain the server socket
+   buffer.  Resets the sequence number.  */
+static void
+test_call_flush (CLIENT *clnt)
+{
+  /* This needs a longer timeout to flush out all pending requests.
+     The choice of 5 seconds is larger than the per-response timeouts
+     requested via the timeout_ms field.  */
+  if (test_verbose)
+    printf ("info: flushing pending queries\n");
+  TEST_VERIFY_EXIT (clnt_call (clnt, PROC_RESET_SEQ,
+                               (xdrproc_t) xdr_void, NULL,
+                               (xdrproc_t) xdr_void, NULL,
+                               ((struct timeval) { 5, 0 }))
+                    == RPC_SUCCESS);
+}
+
+/* Return the number seconds since an arbitrary point in time.  */
+static double
+get_ticks (void)
+{
+  {
+    struct timespec ts;
+    if (clock_gettime (CLOCK_MONOTONIC, &ts) == 0)
+      return ts.tv_sec + ts.tv_nsec * 1e-9;
+  }
+  {
+    struct timeval tv;
+    TEST_VERIFY_EXIT (gettimeofday (&tv, NULL) == 0);
+    return tv.tv_sec + tv.tv_usec * 1e-6;
+  }
+}
+
+static void
+test_udp_server (int port)
+{
+  struct sockaddr_in sin =
+    {
+      .sin_family = AF_INET,
+      .sin_addr.s_addr = htonl (INADDR_LOOPBACK),
+      .sin_port = htons (port)
+    };
+  int sock = RPC_ANYSOCK;
+
+  /* The client uses a 1.5 second timeout for retries.  The timeouts
+     are arbitrary, but chosen so that there is a substantial gap
+     between them, but the total time spent waiting is not too
+     large.  */
+  CLIENT *clnt = clntudp_create (&sin, PROGNUM, VERSNUM,
+                                 (struct timeval) { 1, 500 * 1000 },
+                                 &sock);
+  TEST_VERIFY_EXIT (clnt != NULL);
+
+  /* Basic call/response test.  */
+  struct test_response response = test_call
+    (clnt, PROC_ADD,
+     (struct test_query) { .a = 17, .b = 4 },
+     (struct timeval) { 3, 0 });
+  TEST_VERIFY (response.sum == 21);
+  TEST_VERIFY (response.seq == 1);
+
+  /* Check that garbage packets do not interfere with timeout
+     processing.  */
+  double before = get_ticks ();
+  response = test_call
+    (clnt, PROC_ADD,
+     (struct test_query) {
+       .a = 19, .b = 4, .timeout_ms = 500, .garbage_packets = 21,
+     },
+     (struct timeval) { 3, 0 });
+  TEST_VERIFY (response.sum == 23);
+  TEST_VERIFY (response.seq == 2);
+  double after = get_ticks ();
+  if (test_verbose)
+    printf ("info: 21 garbage packets took %f seconds\n", after - before);
+  /* Expected timeout is 0.5 seconds.  Add some slack in case process
+     scheduling delays processing the query or response, but do not
+     accept a retry (which would happen at 1.5 seconds).  */
+  TEST_VERIFY (0.5 <= after - before);
+  TEST_VERIFY (after - before < 1.2);
+  test_call_flush (clnt);
+
+  /* Check that missing a response introduces a 1.5 second timeout, as
+     requested when calling clntudp_create.  */
+  before = get_ticks ();
+  response = test_call
+    (clnt, PROC_ADD,
+     (struct test_query) { .a = 170, .b = 40, .wait_for_seq = 2 },
+     (struct timeval) { 3, 0 });
+  TEST_VERIFY (response.sum == 210);
+  TEST_VERIFY (response.seq == 2);
+  after = get_ticks ();
+  if (test_verbose)
+    printf ("info: skipping one response took %f seconds\n",
+            after - before);
+  /* Expected timeout is 1.5 seconds.  Do not accept a second retry
+     (which would happen at 3 seconds).  */
+  TEST_VERIFY (1.5 <= after - before);
+  TEST_VERIFY (after - before < 2.9);
+  test_call_flush (clnt);
+
+  /* Check that the overall timeout wins against the per-query
+     timeout.  */
+  before = get_ticks ();
+  test_call_timeout
+    (clnt, PROC_ADD,
+     (struct test_query) { .a = 170, .b = 41, .wait_for_seq = 2 },
+     (struct timeval) { 0, 750 * 1000 });
+  after = get_ticks ();
+  if (test_verbose)
+    printf ("info: 0.75 second timeout took %f seconds\n",
+            after - before);
+  TEST_VERIFY (0.75 <= after - before);
+  TEST_VERIFY (after - before < 1.4);
+  test_call_flush (clnt);
+
+  for (int with_garbage = 0; with_garbage < 2; ++with_garbage)
+    {
+      /* Check that no response at all causes the client to bail out.  */
+      before = get_ticks ();
+      test_call_timeout
+        (clnt, PROC_ADD,
+         (struct test_query) {
+           .a = 170, .b = 40, .timeout_ms = 1200,
+           .garbage_packets = with_garbage * 21
+         },
+         (struct timeval) { 0, 750 * 1000 });
+      after = get_ticks ();
+      if (test_verbose)
+        printf ("info: test_udp_server: 0.75 second timeout took %f seconds"
+                " (garbage %d)\n",
+                after - before, with_garbage);
+      TEST_VERIFY (0.75 <= after - before);
+      TEST_VERIFY (after - before < 1.4);
+      test_call_flush (clnt);
+
+      /* As above, but check the total timeout.  */
+      before = get_ticks ();
+      test_call_timeout
+        (clnt, PROC_ADD,
+         (struct test_query) {
+           .a = 170, .b = 40, .timeout_ms = 3000,
+           .garbage_packets = with_garbage * 30
+         },
+         (struct timeval) { 2, 300 * 1000 });
+      after = get_ticks ();
+      if (test_verbose)
+        printf ("info: test_udp_server: 2.3 second timeout took %f seconds"
+                " (garbage %d)\n",
+                after - before, with_garbage);
+      TEST_VERIFY (2.3 <= after - before);
+      TEST_VERIFY (after - before < 3.0);
+      test_call_flush (clnt);
+    }
+
+  TEST_VERIFY_EXIT (clnt_call (clnt, PROC_EXIT,
+                               (xdrproc_t) xdr_void, NULL,
+                               (xdrproc_t) xdr_void, NULL,
+                               ((struct timeval) { 5, 0 }))
+                    == RPC_SUCCESS);
+  clnt_destroy (clnt);
+}
+
+static int
+do_test (void)
+{
+  support_become_root ();
+  support_enter_network_namespace ();
+
+  SVCXPRT *transport = svcudp_create (RPC_ANYSOCK);
+  TEST_VERIFY_EXIT (transport != NULL);
+  TEST_VERIFY (svc_register (transport, PROGNUM, VERSNUM, server_dispatch, 0));
+
+  pid_t pid = xfork ();
+  if (pid == 0)
+    {
+      svc_run ();
+      FAIL_EXIT1 ("supposed to be unreachable");
+    }
+  test_udp_server (transport->xp_port);
+
+  int status;
+  xwaitpid (pid, &status, 0);
+  TEST_VERIFY (WIFEXITED (status) && WEXITSTATUS (status) == EXIT_MARKER);
+
+  SVC_DESTROY (transport);
+  return 0;
+}
+
+/* The minimum run time is around 17 seconds.  */
+#define TIMEOUT 25
+#include <support/test-driver.c>
index 2ace559ae0afc05d814f177dcbc2286c1e63c436..027a663000e5bd206f8b0369de5d64e2b57f0505 100644 (file)
@@ -35,7 +35,12 @@ libsupport-routines = \
   oom_error \
   resolv_test \
   set_fortify_handler \
+  support-xstat \
   support_become_root \
+  support_can_chroot \
+  support_capture_subprocess \
+  support_capture_subprocess_check \
+  support_chroot \
   support_enter_network_namespace \
   support_format_address_family \
   support_format_addrinfo \
@@ -43,17 +48,25 @@ libsupport-routines = \
   support_format_herrno \
   support_format_hostent \
   support_format_netent \
+  support_isolate_in_subprocess \
   support_record_failure \
   support_run_diff \
+  support_shared_allocate \
+  support_write_file_string \
   support_test_main \
   support_test_verify_impl \
   temp_file \
   write_message \
   xaccept \
+  xaccept4 \
   xasprintf \
   xbind \
   xcalloc \
+  xchroot \
+  xclose \
   xconnect \
+  xdlfcn \
+  xdup2 \
   xfclose \
   xfopen \
   xfork \
@@ -61,13 +74,18 @@ libsupport-routines = \
   xlisten \
   xmalloc \
   xmemstream \
+  xmkdir \
   xmmap \
+  xmprotect \
   xmunmap \
+  xopen \
+  xpipe \
   xpoll \
   xpthread_attr_destroy \
   xpthread_attr_init \
   xpthread_attr_setdetachstate \
   xpthread_attr_setstacksize \
+  xpthread_attr_setguardsize \
   xpthread_barrier_destroy \
   xpthread_barrier_init \
   xpthread_barrier_wait \
@@ -89,6 +107,12 @@ libsupport-routines = \
   xpthread_mutexattr_setrobust \
   xpthread_mutexattr_settype \
   xpthread_once \
+  xpthread_rwlock_init \
+  xpthread_rwlock_rdlock \
+  xpthread_rwlock_wrlock \
+  xpthread_rwlock_unlock \
+  xpthread_rwlockattr_init \
+  xpthread_rwlockattr_setkind_np \
   xpthread_sigmask \
   xpthread_spin_lock \
   xpthread_spin_unlock \
@@ -111,6 +135,8 @@ endif
 tests = \
   README-testing \
   tst-support-namespace \
+  tst-support_capture_subprocess \
+  tst-support_format_dns_packet \
   tst-support_record_failure \
 
 ifeq ($(run-built-tests),yes)
@@ -125,4 +151,6 @@ $(objpfx)tst-support_record_failure-2.out: tst-support_record_failure-2.sh \
        $(evaluate-test)
 endif
 
+$(objpfx)tst-support_format_dns_packet: $(common-objpfx)resolv/libresolv.so
+
 include ../Rules
diff --git a/support/capture_subprocess.h b/support/capture_subprocess.h
new file mode 100644 (file)
index 0000000..43caf9b
--- /dev/null
@@ -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
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef SUPPORT_CAPTURE_SUBPROCESS_H
+#define SUPPORT_CAPTURE_SUBPROCESS_H
+
+#include <support/xmemstream.h>
+
+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 */
index 1d244a35576a2e65f3f8e6ae372a4e59c5a341dd..bdcd12952af6c286cebc9ec0916abedff71b77ed 100644 (file)
@@ -51,7 +51,7 @@ __BEGIN_DECLS
     if (expr)                                                   \
       ;                                                         \
     else                                                        \
-      support_test_verify_impl (-1, __FILE__, __LINE__, #expr); \
+      support_test_verify_impl (__FILE__, __LINE__, #expr);     \
   })
 
 /* Record a test failure and exit if EXPR evaluates to false.  */
@@ -60,7 +60,8 @@ __BEGIN_DECLS
     if (expr)                                                   \
       ;                                                         \
     else                                                        \
-      support_test_verify_impl (1, __FILE__, __LINE__, #expr);  \
+      support_test_verify_exit_impl                             \
+        (1, __FILE__, __LINE__, #expr);                         \
   })
 
 int support_print_failure_impl (const char *file, int line,
@@ -70,8 +71,11 @@ void support_exit_failure_impl (int exit_status,
                                 const char *file, int line,
                                 const char *format, ...)
   __attribute__ ((noreturn, nonnull (2), format (printf, 4, 5)));
-void support_test_verify_impl (int status, const char *file, int line,
+void support_test_verify_impl (const char *file, int line,
                                const char *expr);
+void support_test_verify_exit_impl (int status, const char *file, int line,
+                                    const char *expr)
+  __attribute__ ((noreturn));
 
 /* Record a test failure.  This function returns and does not
    terminate the process.  The failure counter is stored in a shared
index 6bc82d619b9f8478e422cee40b33e3faf0bd63a0..9eddb1a0e904170d2b2f0128520e89267f496bed 100644 (file)
@@ -35,6 +35,13 @@ __BEGIN_DECLS
    single-threaded processes.  */
 bool support_become_root (void);
 
+/* Return true if this process can perform a chroot operation.  In
+   general, this is only possible if support_become_root has been
+   called.  Note that the actual test is performed in a subprocess,
+   after fork, so that the file system root of the original process is
+   not changed.  */
+bool support_can_chroot (void);
+
 /* Enter a network namespace (and a UTS namespace if possible) and
    configure the loopback interface.  Return true if a network
    namespace could be created.  Print diagnostics to standard output.
@@ -48,6 +55,48 @@ bool support_enter_network_namespace (void);
    UTS namespace.  */
 bool support_in_uts_namespace (void);
 
+/* Invoke CALLBACK (CLOSURE) in a subprocess created using fork.
+   Terminate the calling process if the subprocess exits with a
+   non-zero exit status.  */
+void support_isolate_in_subprocess (void (*callback) (void *), void *closure);
+
+/* Describe the setup of a chroot environment, for
+   support_chroot_create below.  */
+struct support_chroot_configuration
+{
+  /* File contents.  The files are not created if the field is
+     NULL.  */
+  const char *resolv_conf;      /* /etc/resolv.conf.  */
+  const char *hosts;            /* /etc/hosts.  */
+  const char *host_conf;        /* /etc/host.conf.  */
+};
+
+/* The result of the creation of a chroot.  */
+struct support_chroot
+{
+  /* Path information.  All these paths are relative to the parent
+     chroot.  */
+
+  /* Path to the chroot directory.  */
+  char *path_chroot;
+
+  /* Paths to files in the chroot.  These are absolute and outside of
+     the chroot.  */
+  char *path_resolv_conf;       /* /etc/resolv.conf.  */
+  char *path_hosts;             /* /etc/hosts.  */
+  char *path_host_conf;         /* /etc/host.conf.  */
+};
+
+/* Create a chroot environment.  The returned data should be freed
+   using support_chroot_free below.  The files will be deleted when
+   the process exits.  This function does not enter the chroot.  */
+struct support_chroot *support_chroot_create
+  (struct support_chroot_configuration);
+
+/* Deallocate the chroot information created by
+   support_chroot_create.  */
+void support_chroot_free (struct support_chroot *);
+
 __END_DECLS
 
 #endif
index 2d0ea3c17cd1cb62a34b1e0f72c331c22c87cf52..1625dcf43a204434d395a6fbf8524d06c5f403fc 100644 (file)
 #include <support/test-driver.h>
 #include <support/xsocket.h>
 #include <support/xthread.h>
+#include <support/xunistd.h>
+#include <sys/uio.h>
 #include <unistd.h>
 
-/* Response builder. */
+/* Response builder.  */
 
 enum
   {
@@ -428,6 +430,7 @@ struct query_info
   char qname[MAXDNAME];
   uint16_t qclass;
   uint16_t qtype;
+  struct resolv_edns_info edns;
 };
 
 /* Update *INFO from the specified DNS packet.  */
@@ -435,10 +438,26 @@ static void
 parse_query (struct query_info *info,
              const unsigned char *buffer, size_t length)
 {
-  if (length < 12)
+  HEADER hd;
+  _Static_assert (sizeof (hd) == 12, "DNS header size");
+  if (length < sizeof (hd))
     FAIL_EXIT1 ("malformed DNS query: too short: %zu bytes", length);
-
-  int ret = dn_expand (buffer, buffer + length, buffer + 12,
+  memcpy (&hd, buffer, sizeof (hd));
+
+  if (ntohs (hd.qdcount) != 1)
+    FAIL_EXIT1 ("malformed DNS query: wrong question count: %d",
+                (int) ntohs (hd.qdcount));
+  if (ntohs (hd.ancount) != 0)
+    FAIL_EXIT1 ("malformed DNS query: wrong answer count: %d",
+                (int) ntohs (hd.ancount));
+  if (ntohs (hd.nscount) != 0)
+    FAIL_EXIT1 ("malformed DNS query: wrong authority count: %d",
+                (int) ntohs (hd.nscount));
+  if (ntohs (hd.arcount) > 1)
+    FAIL_EXIT1 ("malformed DNS query: wrong additional count: %d",
+                (int) ntohs (hd.arcount));
+
+  int ret = dn_expand (buffer, buffer + length, buffer + sizeof (hd),
                        info->qname, sizeof (info->qname));
   if (ret < 0)
     FAIL_EXIT1 ("malformed DNS query: cannot uncompress QNAME");
@@ -456,6 +475,37 @@ parse_query (struct query_info *info,
   memcpy (&qtype_qclass, buffer + 12 + ret, sizeof (qtype_qclass));
   info->qclass = ntohs (qtype_qclass.qclass);
   info->qtype = ntohs (qtype_qclass.qtype);
+
+  memset (&info->edns, 0, sizeof (info->edns));
+  if (ntohs (hd.arcount) > 0)
+    {
+      /* Parse EDNS record.  */
+      struct __attribute__ ((packed, aligned (1)))
+      {
+        uint8_t root;
+        uint16_t rtype;
+        uint16_t payload;
+        uint8_t edns_extended_rcode;
+        uint8_t edns_version;
+        uint16_t flags;
+        uint16_t rdatalen;
+      } rr;
+      _Static_assert (sizeof (rr) == 11, "EDNS record size");
+
+      if (remaining < 4 + sizeof (rr))
+        FAIL_EXIT1 ("mailformed DNS query: no room for EDNS record");
+      memcpy (&rr, buffer + 12 + ret + 4, sizeof (rr));
+      if (rr.root != 0)
+        FAIL_EXIT1 ("malformed DNS query: invalid OPT RNAME: %d\n", rr.root);
+      if (rr.rtype != htons (41))
+        FAIL_EXIT1 ("malformed DNS query: invalid OPT type: %d\n",
+                    ntohs (rr.rtype));
+      info->edns.active = true;
+      info->edns.extended_rcode = rr.edns_extended_rcode;
+      info->edns.version = rr.edns_version;
+      info->edns.flags = ntohs (rr.flags);
+      info->edns.payload_size = ntohs (rr.payload);
+    }
 }
 
 
@@ -585,6 +635,7 @@ server_thread_udp_process_one (struct resolv_test *obj, int server_index)
       .query_length = length,
       .server_index = server_index,
       .tcp = false,
+      .edns = qinfo.edns,
     };
   struct resolv_response_builder *b = response_builder_allocate (query, length);
   obj->config.response_callback
@@ -820,6 +871,7 @@ server_thread_tcp_client (void *arg)
           .query_length = query_length,
           .server_index = closure->server_index,
           .tcp = true,
+          .edns = qinfo.edns,
         };
       struct resolv_response_builder *b = response_builder_allocate
         (query_buffer, query_length);
@@ -860,7 +912,7 @@ server_thread_tcp_client (void *arg)
         break;
     }
 
-  close (closure->client_socket);
+  xclose (closure->client_socket);
   free (closure);
   return NULL;
 }
@@ -881,7 +933,7 @@ server_thread_tcp (struct resolv_test *obj, int server_index)
       if (obj->termination_requested)
         {
           xpthread_mutex_unlock (&obj->lock);
-          close (client_socket);
+          xclose (client_socket);
           break;
         }
       xpthread_mutex_unlock (&obj->lock);
@@ -941,8 +993,8 @@ make_server_sockets (struct resolv_test_server *server)
              next local UDP address randomly.  */
           if (errno == EADDRINUSE)
             {
-              close (server->socket_udp);
-              close (server->socket_tcp);
+              xclose (server->socket_udp);
+              xclose (server->socket_tcp);
               continue;
             }
           FAIL_EXIT1 ("TCP bind: %m");
@@ -952,6 +1004,29 @@ make_server_sockets (struct resolv_test_server *server)
     }
 }
 
+/* Like make_server_sockets, but the caller supplies the address to
+   use.  */
+static void
+make_server_sockets_for_address (struct resolv_test_server *server,
+                                 const struct sockaddr *addr)
+{
+  server->socket_udp = xsocket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+  server->socket_tcp = xsocket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+
+  if (addr->sa_family == AF_INET)
+    server->address = *(const struct sockaddr_in *) addr;
+  else
+    /* We cannot store the server address in the socket.  This should
+       not matter if disable_redirect is used.  */
+    server->address = (struct sockaddr_in) { .sin_family = 0, };
+
+  xbind (server->socket_udp,
+         (struct sockaddr *)&server->address, sizeof (server->address));
+  xbind (server->socket_tcp,
+         (struct sockaddr *)&server->address, sizeof (server->address));
+  xlisten (server->socket_tcp, 5);
+}
+
 /* One-time initialization of NSS.  */
 static void
 resolv_redirect_once (void)
@@ -1012,11 +1087,17 @@ resolv_test_start (struct resolv_redirect_config config)
     .lock = PTHREAD_MUTEX_INITIALIZER,
   };
 
-  resolv_test_init ();
+  if (!config.disable_redirect)
+    resolv_test_init ();
 
   /* Create all the servers, to reserve the necessary ports.  */
   for (int server_index = 0; server_index < config.nscount; ++server_index)
-    make_server_sockets (obj->servers + server_index);
+    if (config.disable_redirect && config.server_address_overrides != NULL)
+      make_server_sockets_for_address
+        (obj->servers + server_index,
+         config.server_address_overrides[server_index]);
+    else
+      make_server_sockets (obj->servers + server_index);
 
   /* Start server threads.  Disable the server ports, as
      requested.  */
@@ -1025,7 +1106,7 @@ resolv_test_start (struct resolv_redirect_config config)
       struct resolv_test_server *server = obj->servers + server_index;
       if (config.servers[server_index].disable_udp)
         {
-          close (server->socket_udp);
+          xclose (server->socket_udp);
           server->socket_udp = -1;
         }
       else if (!config.single_thread_udp)
@@ -1033,7 +1114,7 @@ resolv_test_start (struct resolv_redirect_config config)
                                                   server_thread_udp);
       if (config.servers[server_index].disable_tcp)
         {
-          close (server->socket_tcp);
+          xclose (server->socket_tcp);
           server->socket_tcp = -1;
         }
       else
@@ -1043,6 +1124,9 @@ resolv_test_start (struct resolv_redirect_config config)
   if (config.single_thread_udp)
     start_server_thread_udp_single (obj);
 
+  if (config.disable_redirect)
+    return obj;
+
   int timeout = 1;
 
   /* Initialize libresolv.  */
@@ -1077,6 +1161,7 @@ resolv_test_start (struct resolv_redirect_config config)
     }
   for (int server_index = 0; server_index < config.nscount; ++server_index)
     {
+      TEST_VERIFY_EXIT (obj->servers[server_index].address.sin_port != 0);
       _res.nsaddr_list[server_index] = obj->servers[server_index].address;
       if (test_verbose)
         {
@@ -1114,7 +1199,7 @@ resolv_test_end (struct resolv_test *obj)
           xsendto (sock, "", 1, 0,
                    (struct sockaddr *) &obj->servers[server_index].address,
                    sizeof (obj->servers[server_index].address));
-          close (sock);
+          xclose (sock);
         }
       if (!obj->config.servers[server_index].disable_tcp)
         {
@@ -1122,7 +1207,7 @@ resolv_test_end (struct resolv_test *obj)
           xconnect (sock,
                     (struct sockaddr *) &obj->servers[server_index].address,
                     sizeof (obj->servers[server_index].address));
-          close (sock);
+          xclose (sock);
         }
     }
 
@@ -1137,12 +1222,12 @@ resolv_test_end (struct resolv_test *obj)
         {
           if (!obj->config.single_thread_udp)
             xpthread_join (obj->servers[server_index].thread_udp);
-          close (obj->servers[server_index].socket_udp);
+          xclose (obj->servers[server_index].socket_udp);
         }
       if (!obj->config.servers[server_index].disable_tcp)
         {
           xpthread_join (obj->servers[server_index].thread_tcp);
-          close (obj->servers[server_index].socket_tcp);
+          xclose (obj->servers[server_index].socket_tcp);
         }
     }
 
index 7a9f1f7ae867d4771176fa45430537652819c982..b953dc12000742465b75a2092f95c92718318ab5 100644 (file)
 
 __BEGIN_DECLS
 
+/* Information about EDNS properties of a DNS query.  */
+struct resolv_edns_info
+{
+  bool active;
+  uint8_t extended_rcode;
+  uint8_t version;
+  uint16_t flags;
+  uint16_t payload_size;
+};
+
 /* This struct provides context information when the response callback
    specified in struct resolv_redirect_config is invoked. */
 struct resolv_response_context
@@ -33,6 +43,7 @@ struct resolv_response_context
   size_t query_length;
   int server_index;
   bool tcp;
+  struct resolv_edns_info edns;
 };
 
 /* This opaque struct is used to construct responses from within the
@@ -82,6 +93,16 @@ struct resolv_redirect_config
      may results in more predictable ordering of queries and
      responses.  */
   bool single_thread_udp;
+
+  /* Do not rewrite the _res variable or change NSS defaults.  Use
+     server_address_overrides below to tell the testing framework on
+     which addresses to create the servers.  */
+  bool disable_redirect;
+
+  /* Use these addresses for creating the DNS servers.  The array must
+     have ns_count (or resolv_max_test_servers) sockaddr * elements if
+     not NULL.  */
+  const struct sockaddr *const *server_address_overrides;
 };
 
 /* Configure NSS to use, nss_dns only for aplicable databases, and try
diff --git a/support/support-xstat.c b/support/support-xstat.c
new file mode 100644 (file)
index 0000000..86a81ec
--- /dev/null
@@ -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
+   <http://www.gnu.org/licenses/>.  */
+
+/* NB: Non-standard file name to avoid sysdeps override for xstat.  */
+
+#include <support/check.h>
+#include <support/xunistd.h>
+#include <sys/stat.h>
+
+void
+xstat (const char *path, struct stat64 *result)
+{
+  if (stat64 (path, result) != 0)
+    FAIL_EXIT1 ("stat64 (\"%s\"): %m", path);
+}
index 7292e2a5645c66295be5c0bc3b5c56a7c753143b..4b5f04c2ccc2c419d5f77d685c5a6a24dc30c674 100644 (file)
@@ -44,6 +44,21 @@ void set_fortify_handler (void (*handler) (int sig));
 void oom_error (const char *function, size_t size)
   __attribute__ ((nonnull (1)));
 
+/* Return a pointer to a memory region of SIZE bytes.  The memory is
+   initialized to zero and will be shared with subprocesses (across
+   fork).  The returned pointer must be freed using
+   support_shared_free; it is not compatible with the malloc
+   functions.  */
+void *support_shared_allocate (size_t size);
+
+/* Deallocate a pointer returned by support_shared_allocate.  */
+void support_shared_free (void *);
+
+/* Write CONTENTS to the file PATH.  Create or truncate the file as
+   needed.  The file mode is 0666 masked by the umask.  Terminate the
+   process on error.  */
+void support_write_file_string (const char *path, const char *contents);
+
 /* Error-checking wrapper functions which terminate the process on
    error.  */
 
diff --git a/support/support_can_chroot.c b/support/support_can_chroot.c
new file mode 100644 (file)
index 0000000..0dfd2de
--- /dev/null
@@ -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
+   <http://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <stdio.h>
+#include <support/check.h>
+#include <support/namespace.h>
+#include <support/support.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <xunistd.h>
+
+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 (file)
index 0000000..030f124
--- /dev/null
@@ -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
+   <http://www.gnu.org/licenses/>.  */
+
+#include <support/capture_subprocess.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <support/check.h>
+#include <support/xunistd.h>
+#include <support/xsocket.h>
+
+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 (file)
index 0000000..e1cf73b
--- /dev/null
@@ -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
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <support/capture_subprocess.h>
+#include <support/check.h>
+
+static void
+print_context (const char *context, bool *failed)
+{
+  if (*failed)
+    /* Do not duplicate message.  */
+    return;
+  support_record_failure ();
+  printf ("error: subprocess failed: %s\n", context);
+}
+
+void
+support_capture_subprocess_check (struct support_capture_subprocess *proc,
+                                  const char *context, int status,
+                                  int allowed)
+{
+  TEST_VERIFY ((allowed & sc_allow_none)
+               || (allowed & sc_allow_stdout)
+               || (allowed & sc_allow_stderr));
+  TEST_VERIFY (!((allowed & sc_allow_none)
+                 && ((allowed & sc_allow_stdout)
+                     || (allowed & sc_allow_stderr))));
+
+  bool failed = false;
+  if (proc->status != status)
+    {
+      print_context (context, &failed);
+      printf ("error:   expected exit status: %d\n", status);
+      printf ("error:   actual exit status:   %d\n", proc->status);
+    }
+  if (!(allowed & sc_allow_stdout) && proc->out.length != 0)
+    {
+      print_context (context, &failed);
+      printf ("error:   unexpected output from subprocess\n");
+      fwrite (proc->out.buffer, proc->out.length, 1, stdout);
+      puts ("\n");
+    }
+  if (!(allowed & sc_allow_stderr) && proc->err.length != 0)
+    {
+      print_context (context, &failed);
+      printf ("error:   unexpected error output from subprocess\n");
+      fwrite (proc->err.buffer, proc->err.length, 1, stdout);
+      puts ("\n");
+    }
+}
diff --git a/support/support_chroot.c b/support/support_chroot.c
new file mode 100644 (file)
index 0000000..f3ef551
--- /dev/null
@@ -0,0 +1,85 @@
+/* Setup a chroot environment for use within tests.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stdlib.h>
+#include <support/check.h>
+#include <support/namespace.h>
+#include <support/support.h>
+#include <support/temp_file.h>
+#include <support/test-driver.h>
+#include <support/xunistd.h>
+
+/* If CONTENTS is not NULL, write it to the file at DIRECTORY/RELPATH,
+   and store the name in *ABSPATH.  If CONTENTS is NULL, store NULL in
+   *ABSPATH.  */
+static void
+write_file (const char *directory, const char *relpath, const char *contents,
+            char **abspath)
+{
+  if (contents != NULL)
+    {
+      *abspath = xasprintf ("%s/%s", directory, relpath);
+      add_temp_file (*abspath);
+      support_write_file_string (*abspath, contents);
+    }
+  else
+    *abspath = NULL;
+}
+
+struct support_chroot *
+support_chroot_create (struct support_chroot_configuration conf)
+{
+  struct support_chroot *chroot = xmalloc (sizeof (*chroot));
+
+  chroot->path_chroot = xasprintf ("%s/tst-resolv-res_init-XXXXXX", test_dir);
+  if (mkdtemp (chroot->path_chroot) == NULL)
+    FAIL_EXIT1 ("mkdtemp (\"%s\"): %m", chroot->path_chroot);
+  add_temp_file (chroot->path_chroot);
+
+  /* Create the /etc directory in the chroot environment.  */
+  char *path_etc = xasprintf ("%s/etc", chroot->path_chroot);
+  xmkdir (path_etc, 0777);
+  add_temp_file (path_etc);
+
+  write_file (path_etc, "resolv.conf", conf.resolv_conf,
+              &chroot->path_resolv_conf);
+  write_file (path_etc, "hosts", conf.hosts, &chroot->path_hosts);
+  write_file (path_etc, "host.conf", conf.host_conf, &chroot->path_host_conf);
+
+  free (path_etc);
+
+  /* valgrind needs a temporary directory in the chroot.  */
+  {
+    char *path_tmp = xasprintf ("%s/tmp", chroot->path_chroot);
+    xmkdir (path_tmp, 0777);
+    add_temp_file (path_tmp);
+    free (path_tmp);
+  }
+
+  return chroot;
+}
+
+void
+support_chroot_free (struct support_chroot *chroot)
+{
+  free (chroot->path_chroot);
+  free (chroot->path_resolv_conf);
+  free (chroot->path_hosts);
+  free (chroot->path_host_conf);
+  free (chroot);
+}
index d2e78fe56083358d0f38e9f25f9bed0b27bb7b02..28b0ee29cffe00e44ba09ff57f65f2f3ed253c78 100644 (file)
 #include <stdio.h>
 #include <string.h>
 #include <support/check.h>
+#include <support/xsocket.h>
+#include <support/xunistd.h>
 #include <sys/ioctl.h>
 #include <unistd.h>
-#include <xsocket.h>
 
 static bool in_uts_namespace;
 
@@ -58,7 +59,7 @@ support_enter_network_namespace (void)
           req.ifr_flags |= IFF_UP | IFF_RUNNING;
           TEST_VERIFY_EXIT (ioctl (fd, SIOCSIFFLAGS, &req) == 0);
         }
-      close (fd);
+      xclose (fd);
 
       return !already_up;
     }
index 262e0df7379024afe8523615f77b1633ad121388..eedb0305911a46afbe5183fc7f82e83987e2fb2a 100644 (file)
@@ -39,8 +39,8 @@ socket_address_length (int family)
 }
 
 static void
-format_ai_flags (FILE *out, struct addrinfo *ai, int flag, const char *name,
-                 int * flags_printed)
+format_ai_flags_1 (FILE *out, struct addrinfo *ai, int flag, const char *name,
+                   int * flags_printed)
 {
   if ((ai->ai_flags & flag) != 0)
     fprintf (out, " %s", name);
@@ -48,14 +48,16 @@ format_ai_flags (FILE *out, struct addrinfo *ai, int flag, const char *name,
 }
 
 static void
-format_ai_one (FILE *out, struct addrinfo *ai, int *flags)
+format_ai_flags (FILE *out, struct addrinfo *ai)
 {
-  /* ai_flags */
-  if (ai->ai_flags != *flags)
+  if (ai == NULL)
+    return;
+
+  if (ai->ai_flags != 0)
     {
       fprintf (out, "flags:");
       int flags_printed = 0;
-#define FLAG(flag) format_ai_flags (out, ai, flag, #flag, &flags_printed)
+#define FLAG(flag) format_ai_flags_1 (out, ai, flag, #flag, &flags_printed)
       FLAG (AI_PASSIVE);
       FLAG (AI_CANONNAME);
       FLAG (AI_NUMERICHOST);
@@ -72,9 +74,47 @@ format_ai_one (FILE *out, struct addrinfo *ai, int *flags)
       if (remaining != 0)
         fprintf (out, " %08x", remaining);
       fprintf (out, "\n");
-      *flags = ai->ai_flags;
     }
 
+  /* Report flag mismatches within the list.  */
+  int flags = ai->ai_flags;
+  int index = 1;
+  ai = ai->ai_next;
+  while (ai != NULL)
+    {
+      if (ai->ai_flags != flags)
+        fprintf (out, "error: flags at %d: 0x%x expected, 0x%x actual\n",
+                 index, flags, ai->ai_flags);
+      ai = ai->ai_next;
+      ++index;
+    }
+}
+
+static void
+format_ai_canonname (FILE *out, struct addrinfo *ai)
+{
+  if (ai == NULL)
+    return;
+  if (ai->ai_canonname != NULL)
+    fprintf (out, "canonname: %s\n", ai->ai_canonname);
+
+  /* Report incorrectly set ai_canonname fields on subsequent list
+     entries.  */
+  int index = 1;
+  ai = ai->ai_next;
+  while (ai != NULL)
+    {
+      if (ai->ai_canonname != NULL)
+        fprintf (out, "error: canonname set at %d: %s\n",
+                 index, ai->ai_canonname);
+      ai = ai->ai_next;
+      ++index;
+    }
+}
+
+static void
+format_ai_one (FILE *out, struct addrinfo *ai)
+{
   {
     char type_buf[32];
     const char *type_str;
@@ -156,20 +196,16 @@ format_ai_one (FILE *out, struct addrinfo *ai, int *flags)
     else
       fprintf (out, " %s %u\n", buf, ntohs (port));
   }
-
-  /* ai_canonname */
-  if (ai->ai_canonname != NULL)
-    fprintf (out, "canonname: %s\n", ai->ai_canonname);
 }
 
 /* Format all the addresses in one address family.  */
 static void
-format_ai_family (FILE *out, struct addrinfo *ai, int family, int *flags)
+format_ai_family (FILE *out, struct addrinfo *ai, int family)
 {
   while (ai)
     {
       if (ai->ai_family == family)
-        format_ai_one (out, ai, flags);
+        format_ai_one (out, ai);
       ai = ai->ai_next;
     }
 }
@@ -192,9 +228,10 @@ support_format_addrinfo (struct addrinfo *ai, int ret)
     }
   else
     {
-      int flags = 0;
-      format_ai_family (mem.out, ai, AF_INET, &flags);
-      format_ai_family (mem.out, ai, AF_INET6, &flags);
+      format_ai_flags (mem.out, ai);
+      format_ai_canonname (mem.out, ai);
+      format_ai_family (mem.out, ai, AF_INET);
+      format_ai_family (mem.out, ai, AF_INET6);
     }
 
   xfclose_memstream (&mem);
index 21fe7e5c8df70a4aee8e103328e179e2ed6f6085..2992c579717e19da3ce24055b6d5de131c10e3c0 100644 (file)
@@ -174,7 +174,7 @@ support_format_dns_packet (const unsigned char *buffer, size_t length)
           goto out;
         }
       /* Skip non-matching record types.  */
-      if (rtype != qtype || rclass != qclass)
+      if ((rtype != qtype && rtype != T_CNAME) || rclass != qclass)
         continue;
       switch (rtype)
         {
@@ -186,22 +186,29 @@ support_format_dns_packet (const unsigned char *buffer, size_t length)
                        rdata.data[2],
                        rdata.data[3]);
           else
-            fprintf (mem.out, "error: A record of size %d: %s\n", rdlen, rname.name);
+            fprintf (mem.out, "error: A record of size %d: %s\n",
+                     rdlen, rname.name);
           break;
         case T_AAAA:
           {
-            char buf[100];
-            if (inet_ntop (AF_INET6, rdata.data, buf, sizeof (buf)) == NULL)
-              fprintf (mem.out, "error: AAAA record decoding failed: %m\n");
+            if (rdlen == 16)
+              {
+                char buf[100];
+                if (inet_ntop (AF_INET6, rdata.data, buf, sizeof (buf)) == NULL)
+                  fprintf (mem.out, "error: AAAA record decoding failed: %m\n");
+                else
+                  fprintf (mem.out, "address: %s\n", buf);
+              }
             else
-              fprintf (mem.out, "address: %s\n", buf);
+              fprintf (mem.out, "error: AAAA record of size %d: %s\n",
+                       rdlen, rname.name);
           }
           break;
         case T_CNAME:
         case T_PTR:
           {
             struct dname name;
-            if (extract_name (full, &in, &name))
+            if (extract_name (full, &rdata, &name))
               fprintf (mem.out, "name: %s\n", name.name);
             else
               fprintf (mem.out, "error: malformed CNAME/PTR record\n");
index 5b5f26082efa69330321c8fe55a77c60d0e95547..88c85ec1f1f31e450528f5644d49cdfa43c9b027 100644 (file)
@@ -19,6 +19,7 @@
 #include <support/format_nss.h>
 
 #include <arpa/inet.h>
+#include <errno.h>
 #include <stdio.h>
 #include <support/support.h>
 #include <support/xmemstream.h>
@@ -41,10 +42,15 @@ support_format_hostent (struct hostent *h)
 {
   if (h == NULL)
     {
-      char *value = support_format_herrno (h_errno);
-      char *result = xasprintf ("error: %s\n", value);
-      free (value);
-      return result;
+      if (h_errno == NETDB_INTERNAL)
+        return xasprintf ("error: NETDB_INTERNAL (errno %d, %m)\n", errno);
+      else
+        {
+          char *value = support_format_herrno (h_errno);
+          char *result = xasprintf ("error: %s\n", value);
+          free (value);
+          return result;
+        }
     }
 
   struct xmemstream mem;
diff --git a/support/support_isolate_in_subprocess.c b/support/support_isolate_in_subprocess.c
new file mode 100644 (file)
index 0000000..cf48614
--- /dev/null
@@ -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
+   <http://www.gnu.org/licenses/>.  */
+
+#include <support/check.h>
+#include <support/xunistd.h>
+
+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);
+}
index 3085037a69612010ce3edf0f82a656aa2d03615c..f5155de72749cacd89e780ab0c654a37f5dffa6a 100644 (file)
@@ -24,8 +24,8 @@
 #include <support/check.h>
 #include <support/support.h>
 #include <support/temp_file.h>
+#include <support/xunistd.h>
 #include <sys/wait.h>
-#include <xunistd.h>
 
 static char *
 write_to_temp_file (const char *prefix, const char *str)
@@ -36,7 +36,7 @@ write_to_temp_file (const char *prefix, const char *str)
   TEST_VERIFY_EXIT (fd >= 0);
   free (template);
   xwrite (fd, str, strlen (str));
-  TEST_VERIFY_EXIT (close (fd) == 0);
+  xclose (fd);
   return name;
 }
 
diff --git a/support/support_shared_allocate.c b/support/support_shared_allocate.c
new file mode 100644 (file)
index 0000000..61d088e
--- /dev/null
@@ -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
+   <http://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <stddef.h>
+#include <support/support.h>
+#include <support/xunistd.h>
+#include <sys/mman.h>
+
+/* 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);
+}
index 914d64f6036aa152beaa84357433d85c3aacefb2..3c411a467b04f4dec279ddb84841d1d2f6d56e70 100644 (file)
@@ -211,7 +211,8 @@ support_test_main (int argc, char **argv, const struct test_config *config)
         mallopt (M_PERTURB, 42);
     }
 
-  while ((opt = getopt_long (argc, argv, "+", options, NULL)) != -1)
+  while ((opt = getopt_long (argc, argv, config->optstring, options, NULL))
+        != -1)
     switch (opt)
       {
       case '?':
index 5bae38f8b1b04e93a01b253d7ea64eedbc0b4126..55ab2111b3d0d7dcb032f8483d18cb1d45b12513 100644 (file)
 #include <stdlib.h>
 
 void
-support_test_verify_impl (int status, const char *file, int line,
-                          const char *expr)
+support_test_verify_impl (const char *file, int line, const char *expr)
 {
   support_record_failure ();
   printf ("error: %s:%d: not true: %s\n", file, line, expr);
-  if (status >= 0)
-    exit (status);
+}
 
+void
+support_test_verify_exit_impl (int status, const char *file, int line,
+                               const char *expr)
+{
+  support_test_verify_impl (file, line, expr);
+  exit (status);
 }
diff --git a/support/support_write_file_string.c b/support/support_write_file_string.c
new file mode 100644 (file)
index 0000000..48e8959
--- /dev/null
@@ -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
+   <http://www.gnu.org/licenses/>.  */
+
+#include <fcntl.h>
+#include <string.h>
+#include <support/check.h>
+#include <xunistd.h>
+
+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);
+}
index f06647a467fbf39809a25acb28c78a61d02c29be..fdb2477ab9e7dd3fe8851a2968a36ea75ec96c75 100644 (file)
 #include <support/support.h>
 
 #include <paths.h>
-#include <search.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 
 /* List of temporary files.  */
 static struct temp_name_list
 {
-  struct qelem q;
+  struct temp_name_list *next;
   char *name;
+  pid_t owner;
 } *temp_name_list;
 
 /* Location of the temporary files.  Set by the test skeleton via
@@ -50,10 +51,9 @@ add_temp_file (const char *name)
   if (newname != NULL)
     {
       newp->name = newname;
-      if (temp_name_list == NULL)
-       temp_name_list = (struct temp_name_list *) &newp->q;
-      else
-       insque (newp, temp_name_list);
+      newp->next = temp_name_list;
+      newp->owner = getpid ();
+      temp_name_list = newp;
     }
   else
     free (newp);
@@ -97,13 +97,22 @@ support_set_test_dir (const char *path)
 void
 support_delete_temp_files (void)
 {
+  pid_t pid = getpid ();
   while (temp_name_list != NULL)
     {
-      remove (temp_name_list->name);
+      /* Only perform the removal if the path was registed in the same
+        process, as identified by the PID.  (This assumes that the
+        parent process which registered the temporary file sticks
+        around, to prevent PID reuse.)  */
+      if (temp_name_list->owner == pid)
+       {
+         if (remove (temp_name_list->name) != 0)
+           printf ("warning: could not remove temporary file: %s: %m\n",
+                   temp_name_list->name);
+       }
       free (temp_name_list->name);
 
-      struct temp_name_list *next
-       = (struct temp_name_list *) temp_name_list->q.q_forw;
+      struct temp_name_list *next = temp_name_list->next;
       free (temp_name_list);
       temp_name_list = next;
     }
@@ -116,9 +125,7 @@ support_print_temp_files (FILE *f)
     {
       struct temp_name_list *n;
       fprintf (f, "temp_files=(\n");
-      for (n = temp_name_list;
-           n != NULL;
-           n = (struct temp_name_list *) n->q.q_forw)
+      for (n = temp_name_list; n != NULL; n = n->next)
         fprintf (f, "  '%s'\n", n->name);
       fprintf (f, ")\n");
     }
index 482066dbeb326bb2b6518649128017e8be3b36e9..47c387c2b485bc8415a17b1ce56fb6f49769a58d 100644 (file)
    has this type:
 
      void CMDLINE_PROCESS (int);
+
+   If the program also to process custom default short command line
+   argument (similar to getopt) it must define CMDLINE_OPTSTRING
+   with the expected options (for instance "vb").
 */
 
 #include <support/test-driver.h>
@@ -151,6 +155,11 @@ main (int argc, char **argv)
 #ifdef CMDLINE_PROCESS
   test_config.cmdline_function = CMDLINE_PROCESS;
 #endif
+#ifdef CMDLINE_OPTSTRING
+  test_config.optstring = "+" CMDLINE_OPTSTRING;
+#else
+  test_config.optstring = "+";
+#endif
 
   return support_test_main (argc, argv, &test_config);
 }
index af1971a9ca10acaf235b86e0cc3d68b07eba64af..a8fe9c3565cddbe3b4fe054202742acafbc43179 100644 (file)
@@ -35,6 +35,7 @@ struct test_config
   int expected_status;   /* Expected exit status.  */
   int expected_signal;   /* If non-zero, expect termination by signal.  */
   char no_mallopt;       /* Boolean flag to disable mallopt.  */
+  const char *optstring; /* Short command line options.  */
 };
 
 enum
index a50b074f5e8e884bcc722c40c6cac0a7019c1435..dbe7cc07c8f8aaa4eb4701362468c5754cffaa7a 100644 (file)
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <errno.h>
+#include <netdb.h>
 #include <stdio.h>
+#include <support/check.h>
 #include <support/namespace.h>
+#include <support/xsocket.h>
+#include <support/xunistd.h>
+
+/* Check that the loopback interface provides multiple addresses which
+   can be used to run independent servers.  */
+static void
+test_localhost_bind (void)
+{
+  printf ("info: testing loopback interface with multiple addresses\n");
+
+  /* Create the two server addresses.  */
+  static const struct addrinfo hints =
+    {
+      .ai_family = AF_INET,
+      .ai_socktype = SOCK_DGRAM,
+      .ai_protocol = IPPROTO_UDP,
+    };
+  struct addrinfo *ai[3];
+  TEST_VERIFY_EXIT (getaddrinfo ("127.0.0.1", "53", &hints, ai + 0) == 0);
+  TEST_VERIFY_EXIT (getaddrinfo ("127.0.0.2", "53", &hints, ai + 1) == 0);
+  TEST_VERIFY_EXIT (getaddrinfo ("127.0.0.3", "53", &hints, ai + 2) == 0);
+
+  /* Create the server scokets and bind them to these addresses.  */
+  int sockets[3];
+  for (int i = 0; i < 3; ++i)
+    {
+      sockets[i] = xsocket
+        (ai[i]->ai_family, ai[i]->ai_socktype, ai[i]->ai_protocol);
+      xbind (sockets[i], ai[i]->ai_addr, ai[i]->ai_addrlen);
+    }
+
+  /* Send two packets to each server.  */
+  int client = xsocket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+  for (int i = 0; i < 3; ++i)
+    {
+      TEST_VERIFY (sendto (client, &i, sizeof (i), 0,
+                           ai[i]->ai_addr, ai[i]->ai_addrlen) == sizeof (i));
+      int j = i + 256;
+      TEST_VERIFY (sendto (client, &j, sizeof (j), 0,
+                           ai[i]->ai_addr, ai[i]->ai_addrlen) == sizeof (j));
+    }
+
+  /* Check that the packets can be received with the expected
+     contents.  Note that the receive calls interleave differently,
+     which hopefully proves that the sockets are, indeed,
+     independent.  */
+  for (int i = 0; i < 3; ++i)
+    {
+      int buf;
+      TEST_VERIFY (recv (sockets[i], &buf, sizeof (buf), 0) == sizeof (buf));
+      TEST_VERIFY (buf == i);
+    }
+  for (int i = 0; i < 3; ++i)
+    {
+      int buf;
+      TEST_VERIFY (recv (sockets[i], &buf, sizeof (buf), 0) == sizeof (buf));
+      TEST_VERIFY (buf == i + 256);
+      /* Check that there is no more data to receive.  */
+      TEST_VERIFY (recv (sockets[i], &buf, sizeof (buf), MSG_DONTWAIT) == -1);
+      TEST_VERIFY (errno == EWOULDBLOCK || errno == EAGAIN);
+    }
+
+  /* Close all sockets and free the addresses.  */
+  for (int i = 0; i < 3; ++i)
+    {
+      freeaddrinfo (ai[i]);
+      xclose (sockets[i]);
+    }
+  xclose (client);
+}
+
 
 static int
 do_test (void)
 {
-  if (support_become_root ())
+  bool root = support_become_root ();
+  if (root)
     printf ("info: acquired root-like privileges\n");
-  if (support_enter_network_namespace ())
+  bool netns = support_enter_network_namespace ();
+  if (netns)
     printf ("info: entered network namespace\n");
   if (support_in_uts_namespace ())
     printf ("info: also entered UTS namespace\n");
+
+  if (root && netns)
+    test_localhost_bind ();
+
   return 0;
 }
 
diff --git a/support/tst-support_capture_subprocess.c b/support/tst-support_capture_subprocess.c
new file mode 100644 (file)
index 0000000..5672fba
--- /dev/null
@@ -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
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/capture_subprocess.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+/* 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 <support/test-driver.c>
diff --git a/support/tst-support_format_dns_packet.c b/support/tst-support_format_dns_packet.c
new file mode 100644 (file)
index 0000000..9c8589c
--- /dev/null
@@ -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
+   <http://www.gnu.org/licenses/>.  */
+
+#include <support/check.h>
+#include <support/format_nss.h>
+#include <support/run_diff.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+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 <support/test-driver.c>
index 175137780a96e83cbef9f1839c740adfe02991f5..2c9372cc2916220e963baba0cc3e09105648e2c6 100644 (file)
@@ -37,7 +37,7 @@ run_test () {
     set -e
     echo "  exit status: $status"
     if test "$output" != "$expected_output" ; then
-       echo "error: unexpected ouput: $output"
+       echo "error: unexpected output: $output"
        exit 1
     fi
     if test "$status" -ne "$expected_status" ; then
@@ -52,9 +52,9 @@ different_status () {
     run_test 1 "error: 1 test failures" $direct --status=1
     run_test 2 "error: 1 test failures" $direct --status=2
     run_test 1 "error: 1 test failures" $direct --status=77
-    run_test 2 "error: tst-support_record_failure.c:108: not true: false
+    run_test 2 "error: tst-support_record_failure.c:109: not true: false
 error: 1 test failures" $direct --test-verify
-    run_test 2 "error: tst-support_record_failure.c:108: not true: false
+    run_test 2 "error: tst-support_record_failure.c:109: not true: false
 info: execution passed failed TEST_VERIFY
 error: 1 test failures" $direct --test-verify --verbose
 }
@@ -62,8 +62,8 @@ error: 1 test failures" $direct --test-verify --verbose
 different_status
 different_status --direct
 
-run_test 1 "error: tst-support_record_failure.c:115: not true: false
+run_test 1 "error: tst-support_record_failure.c:116: not true: false
 error: 1 test failures" --test-verify-exit
 # --direct does not print the summary error message if exit is called.
-run_test 1 "error: tst-support_record_failure.c:115: not true: false" \
+run_test 1 "error: tst-support_record_failure.c:116: not true: false" \
         --direct --test-verify-exit
index 62d8e1f0572da0abe5f3a86d864cb0b776e7a2b4..e739e739c399cb94449449bd14a465f23b4becc3 100644 (file)
@@ -25,6 +25,7 @@
 #include <stdbool.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include <string.h>
 
 static int exit_status_with_failure = -1;
 static bool test_verify;
diff --git a/support/xaccept4.c b/support/xaccept4.c
new file mode 100644 (file)
index 0000000..67dd95e
--- /dev/null
@@ -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
+   <http://www.gnu.org/licenses/>.  */
+
+#include <support/xsocket.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <support/check.h>
+
+int
+xaccept4 (int fd, struct sockaddr *sa, socklen_t *salen, int flags)
+{
+  int clientfd = accept4 (fd, sa, salen, flags);
+  if (clientfd < 0)
+    FAIL_EXIT1 ("accept4 (%d, 0x%x): %m", fd, flags);
+  return clientfd;
+}
diff --git a/support/xchroot.c b/support/xchroot.c
new file mode 100644 (file)
index 0000000..abcc299
--- /dev/null
@@ -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
+   <http://www.gnu.org/licenses/>.  */
+
+#include <support/check.h>
+#include <support/xunistd.h>
+#include <sys/stat.h>
+
+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 (file)
index 0000000..c931e08
--- /dev/null
@@ -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
+   <http://www.gnu.org/licenses/>.  */
+
+#include <support/xunistd.h>
+#include <support/check.h>
+#include <errno.h>
+
+void
+xclose (int fd)
+{
+  if (close (fd) < 0 && errno != EINTR)
+    FAIL_EXIT1 ("close of descriptor %d failed: %m", fd);
+}
diff --git a/support/xdlfcn.c b/support/xdlfcn.c
new file mode 100644 (file)
index 0000000..6e39799
--- /dev/null
@@ -0,0 +1,58 @@
+/* Support functionality for using dlopen/dlclose/dlsym.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <support/check.h>
+#include <support/xdlfcn.h>
+
+void *
+xdlopen (const char *filename, int flags)
+{
+  void *dso = dlopen (filename, flags);
+
+  if (dso == NULL)
+    FAIL_EXIT1 ("error: dlopen: %s\n", dlerror ());
+
+  /* Clear any errors.  */
+  dlerror ();
+
+  return dso;
+}
+
+void *
+xdlsym (void *handle, const char *symbol)
+{
+  void *sym = dlsym (handle, symbol);
+
+  if (sym == NULL)
+    FAIL_EXIT1 ("error: dlsym: %s\n", dlerror ());
+
+  /* Clear any errors.  */
+  dlerror ();
+
+  return sym;
+}
+
+void
+xdlclose (void *handle)
+{
+  if (dlclose (handle) != 0)
+    FAIL_EXIT1 ("error: dlclose: %s\n", dlerror ());
+
+  /* Clear any errors.  */
+  dlerror ();
+}
diff --git a/support/xdlfcn.h b/support/xdlfcn.h
new file mode 100644 (file)
index 0000000..9bdcb38
--- /dev/null
@@ -0,0 +1,34 @@
+/* Support functionality for using dlopen/dlclose/dlsym.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef SUPPORT_DLOPEN_H
+#define SUPPORT_DLOPEN_H
+
+#include <dlfcn.h>
+
+__BEGIN_DECLS
+
+/* Each of these terminates process on failure with relevant error message.  */
+void *xdlopen (const char *filename, int flags);
+void *xdlsym (void *handle, const char *symbol);
+void xdlclose (void *handle);
+
+
+__END_DECLS
+
+#endif /* SUPPORT_DLOPEN_H */
diff --git a/support/xdup2.c b/support/xdup2.c
new file mode 100644 (file)
index 0000000..dc08c94
--- /dev/null
@@ -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
+   <http://www.gnu.org/licenses/>.  */
+
+#include <support/xunistd.h>
+
+#include <support/check.h>
+
+void
+xdup2 (int from, int to)
+{
+  if (dup2 (from, to) < 0)
+    FAIL_EXIT1 ("dup2 (%d, %d): %m", from, to);
+}
diff --git a/support/xmkdir.c b/support/xmkdir.c
new file mode 100644 (file)
index 0000000..ea17d49
--- /dev/null
@@ -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
+   <http://www.gnu.org/licenses/>.  */
+
+#include <support/check.h>
+#include <support/xunistd.h>
+#include <sys/stat.h>
+
+void
+xmkdir (const char *path, mode_t mode)
+{
+  if (mkdir (path, mode) != 0)
+    FAIL_EXIT1 ("mkdir (\"%s\", 0%o): %m", path, mode);
+}
diff --git a/support/xmprotect.c b/support/xmprotect.c
new file mode 100644 (file)
index 0000000..9410251
--- /dev/null
@@ -0,0 +1,28 @@
+/* mprotect with error checking.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <support/check.h>
+#include <support/xunistd.h>
+#include <sys/mman.h>
+
+void
+xmprotect (void *addr, size_t length, int prot)
+{
+  if (mprotect (addr, length, prot) != 0)
+    FAIL_EXIT1 ("mprotect (%p, %zu, 0x%x): %m", addr, length, prot);
+}
diff --git a/support/xopen.c b/support/xopen.c
new file mode 100644 (file)
index 0000000..7f033a0
--- /dev/null
@@ -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
+   <http://www.gnu.org/licenses/>.  */
+
+#include <support/check.h>
+#include <support/xunistd.h>
+#include <fcntl.h>
+
+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 (file)
index 0000000..89a64a5
--- /dev/null
@@ -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
+   <http://www.gnu.org/licenses/>.  */
+
+#include <support/xunistd.h>
+
+#include <support/check.h>
+
+void
+xpipe (int fds[2])
+{
+  if (pipe (fds) < 0)
+    FAIL_EXIT1 ("pipe: %m");
+}
diff --git a/support/xpthread_attr_setguardsize.c b/support/xpthread_attr_setguardsize.c
new file mode 100644 (file)
index 0000000..35fed5d
--- /dev/null
@@ -0,0 +1,26 @@
+/* pthread_attr_setguardsize with error checking.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <support/xthread.h>
+
+void
+xpthread_attr_setguardsize (pthread_attr_t *attr, size_t guardsize)
+{
+  xpthread_check_return ("pthread_attr_setguardize",
+                        pthread_attr_setguardsize (attr, guardsize));
+}
diff --git a/support/xpthread_rwlock_init.c b/support/xpthread_rwlock_init.c
new file mode 100644 (file)
index 0000000..824288c
--- /dev/null
@@ -0,0 +1,27 @@
+/* pthread_rwlock_init with error checking.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <support/xthread.h>
+
+void
+xpthread_rwlock_init (pthread_rwlock_t *rwlock,
+                     const pthread_rwlockattr_t *attr)
+{
+  xpthread_check_return ("pthread_rwlock_init",
+                         pthread_rwlock_init (rwlock, attr));
+}
diff --git a/support/xpthread_rwlock_rdlock.c b/support/xpthread_rwlock_rdlock.c
new file mode 100644 (file)
index 0000000..96330a5
--- /dev/null
@@ -0,0 +1,26 @@
+/* pthread_rwlock_rdlock with error checking.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <support/xthread.h>
+
+void
+xpthread_rwlock_rdlock (pthread_rwlock_t *rwlock)
+{
+  xpthread_check_return ("pthread_rwlock_rdlock",
+                        pthread_rwlock_rdlock (rwlock));
+}
diff --git a/support/xpthread_rwlock_unlock.c b/support/xpthread_rwlock_unlock.c
new file mode 100644 (file)
index 0000000..eaa136b
--- /dev/null
@@ -0,0 +1,26 @@
+/* pthread_rwlock_unlock with error checking.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <support/xthread.h>
+
+void
+xpthread_rwlock_unlock (pthread_rwlock_t *rwlock)
+{
+  xpthread_check_return ("pthread_rwlock_unlock",
+                        pthread_rwlock_unlock (rwlock));
+}
diff --git a/support/xpthread_rwlock_wrlock.c b/support/xpthread_rwlock_wrlock.c
new file mode 100644 (file)
index 0000000..8d25d5b
--- /dev/null
@@ -0,0 +1,26 @@
+/* pthread_rwlock_wrlock with error checking.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <support/xthread.h>
+
+void
+xpthread_rwlock_wrlock (pthread_rwlock_t *rwlock)
+{
+  xpthread_check_return ("pthread_rwlock_wrlock",
+                        pthread_rwlock_wrlock (rwlock));
+}
diff --git a/support/xpthread_rwlockattr_init.c b/support/xpthread_rwlockattr_init.c
new file mode 100644 (file)
index 0000000..48baf24
--- /dev/null
@@ -0,0 +1,26 @@
+/* pthread_rwlockattr_init with error checking.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <support/xthread.h>
+
+void
+xpthread_rwlockattr_init (pthread_rwlockattr_t *attr)
+{
+  xpthread_check_return ("pthread_rwlockattr_init",
+                         pthread_rwlockattr_init (attr));
+}
diff --git a/support/xpthread_rwlockattr_setkind_np.c b/support/xpthread_rwlockattr_setkind_np.c
new file mode 100644 (file)
index 0000000..958aace
--- /dev/null
@@ -0,0 +1,27 @@
+/* pthread_rwlockattr_setkind_np with error checking.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <support/xthread.h>
+
+void
+xpthread_rwlockattr_setkind_np (pthread_rwlockattr_t *attr,
+                               int pref)
+{
+  xpthread_check_return ("pthread_rwlockattr_setkind_np",
+                         pthread_rwlockattr_setkind_np (attr, pref));
+}
index 0dbf13ace9d1b3f6b79318bffe35761a8f877d6d..d6724948d8a1f58a4c61c95162bc005d744ee722 100644 (file)
@@ -30,6 +30,7 @@ void xconnect (int, const struct sockaddr *, socklen_t);
 void xbind (int, const struct sockaddr *, socklen_t);
 void xlisten (int, int);
 int xaccept (int, struct sockaddr *, socklen_t *);
+int xaccept4 (int, struct sockaddr *, socklen_t *, int);
 void xsendto (int, const void *, size_t, int,
               const struct sockaddr *, socklen_t);
 size_t xrecvfrom (int, void *, size_t, int, struct sockaddr *, socklen_t *);
index 6dd7e709bec14eef86dbed2085e99aada1757ef1..472763ebe86cfef5e60738b24b915a0188ca4337 100644 (file)
@@ -67,11 +67,21 @@ void xpthread_attr_setdetachstate (pthread_attr_t *attr,
                                   int detachstate);
 void xpthread_attr_setstacksize (pthread_attr_t *attr,
                                 size_t stacksize);
+void xpthread_attr_setguardsize (pthread_attr_t *attr,
+                                size_t guardsize);
 
 /* This function returns non-zero if pthread_barrier_wait returned
    PTHREAD_BARRIER_SERIAL_THREAD.  */
 int xpthread_barrier_wait (pthread_barrier_t *barrier);
 
+void xpthread_rwlock_init (pthread_rwlock_t *rwlock,
+                         const pthread_rwlockattr_t *attr);
+void xpthread_rwlockattr_init (pthread_rwlockattr_t *attr);
+void xpthread_rwlockattr_setkind_np (pthread_rwlockattr_t *attr, int pref);
+void xpthread_rwlock_wrlock (pthread_rwlock_t *rwlock);
+void xpthread_rwlock_rdlock (pthread_rwlock_t *rwlock);
+void xpthread_rwlock_unlock (pthread_rwlock_t *rwlock);
+
 __END_DECLS
 
 #endif /* SUPPORT_THREAD_H */
index a83b1f4541fc3eec79d0148ceab66a45843fd0c7..c947bfd8fb8f443a49cac37945b29789db4ec539 100644 (file)
 #ifndef SUPPORT_XUNISTD_H
 #define SUPPORT_XUNISTD_H
 
-#include <unistd.h>
 #include <sys/cdefs.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 __BEGIN_DECLS
 
+struct stat64;
+
 pid_t xfork (void);
 pid_t xwaitpid (pid_t, int *status, int flags);
+void xpipe (int[2]);
+void xdup2 (int, int);
+int xopen (const char *path, int flags, mode_t);
+void xstat (const char *path, struct stat64 *);
+void xmkdir (const char *path, mode_t);
+void xchroot (const char *path);
+
+/* Close the file descriptor.  Ignore EINTR errors, but terminate the
+   process on other errors.  */
+void xclose (int);
 
 /* Write the buffer.  Retry on short writes.  */
 void xwrite (int, const void *, size_t);
 
 /* Invoke mmap with a zero file offset.  */
 void *xmmap (void *addr, size_t length, int prot, int flags, int fd);
-
+void xmprotect (void *addr, size_t length, int prot);
 void xmunmap (void *addr, size_t length);
 
 __END_DECLS
index 84b8aecfb8ec08d922f78501b1829a4fbe7463d3..6067a1d8a01ddaa65343b615b18361597bcb52dd 100644 (file)
@@ -193,8 +193,8 @@ _dl_start_user:                                                             \n\
        cmp     " PTR "0, #0                                            \n\
        bne     1b                                                      \n\
        // Update _dl_argv                                              \n\
-       adrp    x3, _dl_argv                                            \n\
-       str     " PTR "2, [x3, #:lo12:_dl_argv]                         \n\
+       adrp    x3, __GI__dl_argv                                       \n\
+       str     " PTR "2, [x3, #:lo12:__GI__dl_argv]                    \n\
 .L_done_stack_adjust:                                                  \n\
        // compute envp                                                 \n\
        add     " PTR "3, " PTR "2, " PTR "1, lsl #" PTR_SIZE_LOG "     \n\
index a74083786ef4766735a5bf088b26de161ba5d643..5ea8a4a259ef753c9d0d30aa4c0788e93656d047 100644 (file)
@@ -16,6 +16,7 @@
   "LD_DEBUG\0"                                                               \
   "LD_DEBUG_OUTPUT\0"                                                        \
   "LD_DYNAMIC_WEAK\0"                                                        \
+  "LD_HWCAP_MASK\0"                                                          \
   "LD_LIBRARY_PATH\0"                                                        \
   "LD_ORIGIN_PATH\0"                                                         \
   "LD_PRELOAD\0"                                                             \
index d1e4e6f0d553bf0c630d505f66f05161ba53faa8..52e97e2f6a731e57fa57d304a351977a73b5f601 100644 (file)
 #undef __stat
 #define __stat(file, buf) __xstat64 (_STAT_VER, file, buf)
 
-#define NO_GLOB_PATTERN_P 1
-
 #define COMPILE_GLOB64 1
 
 #include <posix/glob.c>
 
 libc_hidden_def (glob64)
-libc_hidden_def (globfree64)
diff --git a/sysdeps/gnu/globfree64.c b/sysdeps/gnu/globfree64.c
new file mode 100644 (file)
index 0000000..f092d0b
--- /dev/null
@@ -0,0 +1,10 @@
+#include <dirent.h>
+#include <glob.h>
+#include <sys/stat.h>
+
+#define glob_t glob64_t
+#define globfree(pglob) globfree64 (pglob)
+
+#include <posix/globfree.c>
+
+libc_hidden_def (globfree64)
index a7eefc7ad6db7abc1862f6629fa09c0a702b882e..2fedb1d7387411e4bd415208d70262b81c71ed47 100644 (file)
 void
 __longjmp (__jmp_buf env, int val)
 {
+#ifdef CHECK_SP
+  CHECK_SP (env[0].__jmp_buf.__sp);
+#endif
+
   /* We must use one of the non-callee saves registers
      for env.  */
   register unsigned long r26 asm ("r26") = (unsigned long)&env[0];
   register unsigned long r25 asm ("r25") = (unsigned long)(val == 0 ? 1 : val);
 
-#ifdef CHECK_SP
-  CHECK_SP (env[0].__jmp_buf.__sp);
-#endif
-
   asm volatile(
        /* Set return value.  */
        "copy   %0, %%r28\n\t"
@@ -79,6 +79,7 @@ __longjmp (__jmp_buf env, int val)
        : /* No outputs.  */
        : "r" (r25), "r" (r26)
        : /* No point in clobbers.  */ );
+
   /* Avoid `volatile function does return' warnings.  */
   for (;;);
 }
index 83bdb9120237f9ad7559ab3315e50b5f8a64a7dd..f74abc02c29604f1e4a4b23278a0d246a76319a8 100644 (file)
@@ -181,24 +181,29 @@ make_fdesc (ElfW(Addr) ip, ElfW(Addr) gp)
 static inline ElfW(Addr) * __attribute__ ((always_inline))
 make_fptr_table (struct link_map *map)
 {
-  const ElfW(Sym) *symtab
-    = (const void *) D_PTR (map, l_info[DT_SYMTAB]);
+  const ElfW(Sym) *symtab = (const void *) D_PTR (map, l_info[DT_SYMTAB]);
   const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
   ElfW(Addr) *fptr_table;
   size_t size;
   size_t len;
+  const ElfW(Sym) *symtabend;
 
-  /* XXX Apparently the only way to find out the size of the dynamic
-     symbol section is to assume that the string table follows right
-     afterwards...  */
-  len = ((strtab - (char *) symtab)
+  /* Determine the end of the dynamic symbol table using the hash.  */
+  if (map->l_info[DT_HASH] != NULL)
+    symtabend = (symtab + ((Elf_Symndx *) D_PTR (map, l_info[DT_HASH]))[1]);
+  else
+  /* There is no direct way to determine the number of symbols in the
+     dynamic symbol table and no hash table is present.  The ELF
+     binary is ill-formed but what shall we do?  Use the beginning of
+     the string table which generally follows the symbol table.  */
+    symtabend = (const ElfW(Sym) *) strtab;
+
+  len = (((char *) symtabend - (char *) symtab)
         / map->l_info[DT_SYMENT]->d_un.d_val);
-  size = ((len * sizeof (fptr_table[0]) + GLRO(dl_pagesize) - 1)
-         & -GLRO(dl_pagesize));
-  /* XXX We don't support here in the moment systems without MAP_ANON.
-     There probably are none for IA-64.  In case this is proven wrong
-     we will have to open /dev/null here and use the file descriptor
-     instead of the hard-coded -1.  */
+  size = ALIGN_UP (len * sizeof (fptr_table[0]), GLRO(dl_pagesize));
+
+  /* We don't support systems without MAP_ANON.  We avoid using malloc
+     because this might get called before malloc is setup.  */
   fptr_table = __mmap (NULL, size,
                       PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE,
                       -1, 0);
@@ -331,22 +336,45 @@ elf_machine_resolve (void)
   return addr;
 }
 
+static inline int
+_dl_read_access_allowed (unsigned int *addr)
+{
+  int result;
+
+  asm ("proberi        (%1),3,%0" : "=r" (result) : "r" (addr) : );
+
+  return result;
+}
+
 ElfW(Addr)
 _dl_lookup_address (const void *address)
 {
   ElfW(Addr) addr = (ElfW(Addr)) address;
   unsigned int *desc, *gptr;
 
-  /* Check for special cases.  */
-  if ((int) addr == -1
-      || (unsigned int) addr < 4096
-      || !((unsigned int) addr & 2))
+  /* Return ADDR if the least-significant two bits of ADDR are not consistent
+     with ADDR being a linker defined function pointer.  The normal value for
+     a code address in a backtrace is 3.  */
+  if (((unsigned int) addr & 3) != 2)
+    return addr;
+
+  /* Handle special case where ADDR points to page 0.  */
+  if ((unsigned int) addr < 4096)
     return addr;
 
   /* Clear least-significant two bits from descriptor address.  */
   desc = (unsigned int *) ((unsigned int) addr & ~3);
+  if (!_dl_read_access_allowed (desc))
+    return addr;
 
-  /* Check if descriptor requires resolution.  The following trampoline is
+  /* Load first word of candidate descriptor.  It should be a pointer
+     with word alignment and point to memory that can be read.  */
+  gptr = (unsigned int *) desc[0];
+  if (((unsigned int) gptr & 3) != 0
+      || !_dl_read_access_allowed (gptr))
+    return addr;
+
+  /* See if descriptor requires resolution.  The following trampoline is
      used in each global offset table for function resolution:
 
                ldw 0(r20),r22
@@ -358,7 +386,6 @@ _dl_lookup_address (const void *address)
                .word "_dl_runtime_resolve ltp"
      got:      .word _DYNAMIC
                .word "struct link map address" */
-  gptr = (unsigned int *) desc[0];
   if (gptr[0] == 0xea9f1fdd                    /* b,l .-12,r20     */
       && gptr[1] == 0xd6801c1e                 /* depwi 0,31,2,r20 */
       && (ElfW(Addr)) gptr[2] == elf_machine_resolve ())
index 339c7bb771298b93a0c500d2ba25c4a61a1d1610..787b95f5022e0094e630eaad73e5296eedf8d284 100644 (file)
@@ -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"                                \
index 856339bffe1c62d299b2d2c343fe8e2e0fcf4f58..3165c6f0e2528696911408ebd597a117c404b1e3 100644 (file)
@@ -82,6 +82,21 @@ _dl_runtime_resolve:
        bl      _dl_fixup,%rp
        copy    %r21,%r19               /* set fixup func ltp */
 
+       /* While the linker will set a function pointer to NULL when it
+          encounters an undefined weak function, we need to dynamically
+          detect removed weak functions.  The issue arises because a weak
+          __gmon_start__ function was added to shared executables to work
+          around issues in _init that are now resolved.  The presence of
+          __gmon_start__ in every shared library breaks the linker
+          `--as-needed' option.  This __gmon_start__ function does nothing
+          but removal is tricky.  Depending on the binding, removal can
+          cause an application using it to fault.  The call to _dl_fixup
+          returns NULL when a function isn't resolved.  In order to help
+          with __gmon_start__ removal, we return directly to the caller
+          when _dl_fixup returns NULL.  This check could be removed when
+          BZ 19170 is fixed.  */
+       comib,= 0,%r28,1f
+
        /* Load up the returned func descriptor */
        copy    %r28, %r22
        copy    %r29, %r19
@@ -107,6 +122,13 @@ _dl_runtime_resolve:
        /* Jump to new function, but return to previous function */
        bv      %r0(%r22)
        ldw     -20(%sp),%rp
+
+1:
+       /* Return to previous function */
+       ldw     -148(%sp),%rp
+       bv      %r0(%rp)
+       ldo     -128(%sp),%sp
+
         .EXIT
         .PROCEND
        cfi_endproc
diff --git a/sysdeps/hppa/math-tests.h b/sysdeps/hppa/math-tests.h
new file mode 100644 (file)
index 0000000..bb20590
--- /dev/null
@@ -0,0 +1,22 @@
+/* Configuration for math tests.  hppa version.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* SNaN tests do not preserve payloads.  */
+#define SNAN_TESTS_PRESERVE_PAYLOAD 0
+
+#include_next <math-tests.h>
index e37111a2f3afa10a3623a45c56fde6c4ab0d9bee..579047b732bc496dd63f6c5fb027d794939dd8f4 100644 (file)
@@ -106,36 +106,34 @@ typedef union
 
 /* Data structure for conditional variable handling.  The structure of
    the attribute type is not exposed on purpose. However, this structure
-   is exposed via PTHREAD_COND_INITIALIZER, and because of this, the
-   Linuxthreads version sets the first four ints to one. In the NPTL
-   version we must check, in every function using pthread_cond_t,
-   for the static Linuxthreads initializer and clear the appropriate
-   words. */
+   is exposed via PTHREAD_COND_INITIALIZER.  Support for Linuxthreads has
+   been dropped but we still need to retain the alignment of the original
+   lock field from Linuxthreads.  */
 typedef union
 {
   struct
   {
-    /* In the old Linuxthreads pthread_cond_t, this is the
-       start of the 4-word lock structure, the next four words
-       are set all to 1 by the Linuxthreads
-       PTHREAD_COND_INITIALIZER.  */
-    int __lock __attribute__ ((__aligned__(16)));
-    /* Tracks the initialization of this structure:
-       0  initialized with NPTL PTHREAD_COND_INITIALIZER.
-       1  initialized with Linuxthreads PTHREAD_COND_INITIALIZER.
-       2  initialization in progress.  */
-    int __initializer;
-    unsigned int __futex;
-    void *__mutex;
-    /* In the old Linuxthreads this would have been the start
-       of the pthread_fastlock status word.  */
-    __extension__ unsigned long long int __total_seq;
-    __extension__ unsigned long long int __wakeup_seq;
-    __extension__ unsigned long long int __woken_seq;
-    unsigned int __nwaiters;
-    unsigned int __broadcast_seq;
-    /* The NPTL pthread_cond_t is exactly the same size as
-       the Linuxthreads version, there are no words to spare.  */
+    __extension__ union
+    {
+      __extension__ unsigned long long int __wseq;
+      struct {
+       unsigned int __low;
+       unsigned int __high;
+      } __wseq32;
+    };
+    __extension__ union
+    {
+      __extension__ unsigned long long int __g1_start;
+      struct {
+       unsigned int __low;
+       unsigned int __high;
+      } __g1_start32;
+    };
+    unsigned int __g_refs[2] __attribute__ ((__aligned__(16)));
+    unsigned int __g_size[2];
+    unsigned int __g1_orig_size;
+    unsigned int __wrefs;
+    unsigned int __g_signals[2];
   } __data;
   char __size[__SIZEOF_PTHREAD_COND_T];
   __extension__ long long int __align;
index cb82d3ee36d455cce80aabf84f8cd1c2eb3dafcc..275dbbe8042a45e700707d3ca36f2e2f72a1783e 100644 (file)
@@ -42,7 +42,7 @@ ldouble: 4
 Function: "acosh_upward":
 double: 1
 idouble: 1
-ildouble: 4
+ildouble: 5
 ldouble: 3
 
 Function: "asin":
@@ -900,8 +900,8 @@ double: 3
 float: 3
 idouble: 3
 ifloat: 3
-ildouble: 7
-ldouble: 7
+ildouble: 8
+ldouble: 8
 
 Function: Imaginary part of "clog10_upward":
 double: 1
@@ -1591,8 +1591,8 @@ double: 3
 float: 4
 idouble: 3
 ifloat: 4
-ildouble: 5
-ldouble: 5
+ildouble: 6
+ldouble: 6
 
 Function: "hypot":
 double: 1
@@ -1743,8 +1743,8 @@ double: 3
 float: 4
 idouble: 3
 ifloat: 4
-ildouble: 5
-ldouble: 5
+ildouble: 6
+ldouble: 6
 
 Function: "log":
 double: 1
index 910679cfc055c141fd38d120e6ebf4753e395a34..e41f324a7723dcba406684675af521c21a047100 100644 (file)
@@ -117,7 +117,6 @@ L(crosscache):
 
 # ifndef USE_AS_RAWMEMCHR
        jnz     L(match_case2_prolog1)
-       lea     -16(%edx), %edx
         /* Calculate the last acceptable address and check for possible
            addition overflow by using satured math:
            edx = ecx + edx
@@ -125,6 +124,7 @@ L(crosscache):
        add     %ecx, %edx
        sbb     %eax, %eax
        or      %eax, %edx
+       sub     $16, %edx
        jbe     L(return_null)
        lea     16(%edi), %edi
 # else
index 6d61e190a84881c9e42e4d1baafcbee7e6a1ec8b..ec230fb38308b7b0f3f9c72bcba7387864196526 100644 (file)
@@ -1,2 +1,4 @@
-#define __strcspn_sse2 __strcspn_ia32
-#include <sysdeps/x86_64/multiarch/strcspn-c.c>
+#if IS_IN (libc)
+# define __strcspn_sse2 __strcspn_ia32
+# include <sysdeps/x86_64/multiarch/strcspn-c.c>
+#endif
index 7760b966e27d550f106419ef5d594664714d3926..6742a35d41e353d23043a6052d34116bf320ddac 100644 (file)
@@ -1 +1,3 @@
-#include <sysdeps/x86_64/multiarch/varshift.c>
+#if IS_IN (libc)
+# include <sysdeps/x86_64/multiarch/varshift.c>
+#endif
diff --git a/sysdeps/mips/bits/long-double.h b/sysdeps/mips/bits/long-double.h
deleted file mode 100644 (file)
index 604188e..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/* Properties of long double type.  MIPS version.
-   Copyright (C) 2016-2017 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License  published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <http://www.gnu.org/licenses/>.  */
-
-#include <sgidefs.h>
-
-#if !defined __NO_LONG_DOUBLE_MATH && _MIPS_SIM == _ABIO32
-# define __NO_LONG_DOUBLE_MATH 1
-#endif
diff --git a/sysdeps/mips/ieee754/bits/long-double.h b/sysdeps/mips/ieee754/bits/long-double.h
new file mode 100644 (file)
index 0000000..604188e
--- /dev/null
@@ -0,0 +1,23 @@
+/* Properties of long double type.  MIPS version.
+   Copyright (C) 2016-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License  published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <sgidefs.h>
+
+#if !defined __NO_LONG_DOUBLE_MATH && _MIPS_SIM == _ABIO32
+# define __NO_LONG_DOUBLE_MATH 1
+#endif
index db6d721fce9c61446315683389d11619bb60f737..4bb87e233118586f5d277c16fc67806a5255ab1a 100644 (file)
@@ -131,10 +131,6 @@ __libc_fork (void)
       call_function_static_weak (__malloc_fork_lock_parent);
     }
 
-#ifndef NDEBUG
-  pid_t ppid = THREAD_GETMEM (THREAD_SELF, tid);
-#endif
-
 #ifdef ARCH_FORK
   pid = ARCH_FORK ();
 #else
@@ -147,8 +143,6 @@ __libc_fork (void)
     {
       struct pthread *self = THREAD_SELF;
 
-      assert (THREAD_GETMEM (self, tid) != ppid);
-
       /* See __pthread_once.  */
       if (__fork_generation_pointer != NULL)
        *__fork_generation_pointer += __PTHREAD_ONCE_FORK_GEN_INCR;
@@ -230,8 +224,6 @@ __libc_fork (void)
     }
   else
     {
-      assert (THREAD_GETMEM (THREAD_SELF, tid) == ppid);
-
       /* Release acquired locks in the multi-threaded case.  */
       if (multiple_threads)
        {
index f7ecbd105aabe09e23613c08f7c25eaff1921865..3ae383a831bcc0cd2db466d6c2b695dd2cb89235 100644 (file)
@@ -35,14 +35,16 @@ static const union {
 long double
 __logbl (long double x)
 {
-  double xh;
+  double xh, xl;
   double ret;
+  int64_t hx;
 
   if (__builtin_expect (x == 0.0L, 0))
     /* Raise FE_DIVBYZERO and return -HUGE_VAL[LF].  */
     return -1.0L / __builtin_fabsl (x);
 
-  xh = ldbl_high (x);
+  ldbl_unpack (x, &xh, &xl);
+  EXTRACT_WORDS64 (hx, xh);
   /* ret = x & 0x7ff0000000000000;  */
   asm (
     "xxland %x0,%x1,%x2\n"
@@ -58,10 +60,20 @@ __logbl (long double x)
     {
       /* POSIX specifies that denormal number is treated as
          though it were normalized.  */
-      int64_t hx;
-
-      EXTRACT_WORDS64 (hx, xh);
-      return (long double) (-1023 - (__builtin_clzll (hx) - 12));
+      return (long double) (- (__builtin_clzll (hx & 0x7fffffffffffffffLL) \
+                              - 12) - 1023);
+    }
+  else if ((hx & 0x000fffffffffffffLL) == 0)
+    {
+      /* If the high part is a power of 2, and the low part is nonzero
+        with the opposite sign, the low part affects the
+        exponent.  */
+      int64_t lx, rhx;
+      EXTRACT_WORDS64 (lx, xl);
+      rhx = (hx & 0x7ff0000000000000LL) >> 52;
+      if ((hx ^ lx) < 0 && (lx & 0x7fffffffffffffffLL) != 0)
+       rhx--;
+      return (long double) (rhx - 1023);
     }
   /* Test to avoid logb_downward (0.0) == -0.0.  */
   return ret == -0.0 ? 0.0 : ret;
index 28eb50f92db778583c37100c171a7e97d9337b4c..9b5a99fcc7fe8a8043d19d76f2cb56b696ebfce1 100644 (file)
@@ -309,7 +309,10 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
      against local symbols.  */
   if (__builtin_expect (ELF32_ST_BIND (sym->st_info) == STB_LOCAL, 0)
       && sym->st_shndx != SHN_UNDEF)
-    value = map->l_addr;
+    {
+      sym_map = map;
+      value = map->l_addr;
+    }
   else
     {
       sym_map = RESOLVE_MAP (&sym, version, r_type);
index cf7272f359e65eaf8c55188dd5c256b943d91cf9..3e03fd091c7e87e3e1df97983b405048339e7ff5 100644 (file)
@@ -375,6 +375,7 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
   if (__builtin_expect (ELF32_ST_BIND (sym->st_info) == STB_LOCAL, 0)
       && sym->st_shndx != SHN_UNDEF)
     {
+      sym_map = map;
       value = map->l_addr;
     }
   else
index 99c00f493d8fda4f06fe73f99d1ea547754de3aa..0694ac1362e838d24dfa6aca05fa7639d85b5724 100644 (file)
@@ -402,6 +402,7 @@ elf_machine_rela (struct link_map *map, const Elf64_Rela *reloc,
   if (__builtin_expect (ELF64_ST_BIND (sym->st_info) == STB_LOCAL, 0)
       && sym->st_shndx != SHN_UNDEF)
     {
+      sym_map = map;
       value = map->l_addr;
     }
   else
index b3d68665f9d257681c4c0ceb10194a653240b8ee..beb1c291119174ee6578229a4351b1d679fb3e03 100644 (file)
@@ -141,7 +141,7 @@ endif
 ifeq ($(subdir),posix)
 sysdep_headers += bits/initspin.h
 
-sysdep_routines += sched_getcpu
+sysdep_routines += sched_getcpu oldglob
 
 tests += tst-affinity tst-affinity-pid
 
index 2d7d287a25bb811760d3898467b6e407498f3ad6..1b813c1cfdb56f7f197b852518a8311ae86b6b1b 100644 (file)
@@ -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 (file)
index 0000000..98cf1c2
--- /dev/null
@@ -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
+   <http://www.gnu.org/licenses/>.  */
+
+#define globfree64 __no_globfree64_decl
+#include <sys/types.h>
+#include <glob.h>
+#include <shlib-compat.h>
+
+#define globfree(pglob) \
+  __new_globfree (pglob)
+
+extern void __new_globfree (glob_t *__pglob);
+
+#include <posix/globfree.c>
+
+#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)
index cca17f1e34bd81de7bfeb8aba5b141637250b43e..1f0e3b494e9027a42069937fa03700457e98fb84 100644 (file)
@@ -20,7 +20,7 @@ libc.so: free + RELA R_ALPHA_GLOB_DAT
 libc.so: malloc + RELA R_ALPHA_GLOB_DAT
 libc.so: memalign + RELA R_ALPHA_GLOB_DAT
 libc.so: realloc + RELA R_ALPHA_GLOB_DAT
-libm.so: matherr
+libm.so: matherr + RELA R_ALPHA_GLOB_DAT
 # We used to offer inline functions that used this, so it must be exported.
 # Ought to reorg things such that carg isn't thus forced to use a plt.
 libm.so: __atan2
index 794f0ab2da354469f053bdf68535270694f7136e..495dae8afcbc5f5893bb37a472d32d5157df1232 100644 (file)
@@ -37,7 +37,7 @@
 #define SHM_UNLOCK     12              /* unlock segment (root only) */
 
 /* Segment low boundary address multiple.  */
-#define SHMLBA 0x00400000              /* address needs to be 4 Mb aligned */
+#define SHMLBA         0x1000
 
 /* Type to count number of attaches.  */
 typedef unsigned long int shmatt_t;
index d36b3021998e74056f75ac21264d54f52c2c1a8a..f6b4e3eea8aab35106192e80375dfaf34b6123ca 100644 (file)
 ENTRY(__clone)
        /* Prologue */
        stwm    %r4, 64(%sp)
+       .cfi_def_cfa_offset -64
+       .cfi_offset 4, 0
        stw     %sp, -4(%sp)
 #ifdef PIC
        stw     %r19, -32(%sp)
+       .cfi_offset 19, 32
 #endif
 
        /* Sanity check arguments.  */
@@ -147,9 +150,9 @@ ENTRY(__clone)
 #ifdef PIC
        copy    %r4, %r19
 #endif
-       /* The call to _exit needs saved r19.  */
-       bl      _exit, %rp
-       copy    %ret0, %arg0
+       copy    %r28, %r26
+       ble     0x100(%sr2, %r0)
+       ldi     __NR_exit, %r20
 
        /* We should not return from _exit.
            We do not restore r4, or the stack state.  */
index 6f52f2149da30f69b71e0015bf336220f662fe6a..68a74a0b7e46b637005ddc8b0c6271e87c4e5ee8 100644 (file)
@@ -130,8 +130,11 @@ ENTRY(__getcontext)
 
        /* Prologue */
        stwm    %r4, 64(%sp)
+       .cfi_def_cfa_offset -64
+       .cfi_offset 4, 0
 #ifdef PIC
        stw     %r19, -32(%sp)
+       .cfi_offset 19, 32
 #endif
 
        /* Set up the trampoline registers.
@@ -156,7 +159,7 @@ ENTRY(__getcontext)
        /* Epilogue */
        ldw     -84(%sp), %r2
 #ifdef PIC
-       ldw     -96(%sp), %r19
+       ldw     -32(%sp), %r19
 #endif
        bv      %r0(%r2)
        ldwm    -64(%sp), %r4
diff --git a/sysdeps/unix/sysv/linux/hppa/internaltypes.h b/sysdeps/unix/sysv/linux/hppa/internaltypes.h
deleted file mode 100644 (file)
index d649657..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-#include_next <internaltypes.h>
-#ifndef _INTERNAL_TYPES_H_HPPA_
-#define _INTERNAL_TYPES_H_HPPA_ 1
-#include <atomic.h>
-
-/* In GLIBC 2.10 HPPA switched from Linuxthreads to NPTL, and in order
-to maintain ABI compatibility with pthread_cond_t, some care had to be
-taken.
-
-The NPTL pthread_cond_t grew in size. When HPPA switched to NPTL, we
-dropped the use of ldcw, and switched to the kernel helper routine for
-compare-and-swap.  This allowed HPPA to use the 4-word 16-byte aligned
-lock words, and alignment words to store the additional pthread_cond_t
-data. Once organized properly the new NPTL pthread_cond_t was 1 word
-smaller than the Linuxthreads version.
-
-However, we were faced with the case that users may have initialized the
-pthread_cond_t with PTHREAD_COND_INITIALIZER. In this case, the first
-four words were set to one, and must be cleared before any NPTL code
-used these words.
-
-We didn't want to use LDCW, because it continues to be a source of bugs
-when applications memset pthread_cond_t to all zeroes by accident. This
-works on all other architectures where lock words are unlocked at zero.
-Remember that because of the semantics of LDCW, a locked word is set to
-zero, and an unlocked word is set to 1.
-
-Instead we used atomic_compare_and_exchange_val_acq, but we couldn't use
-this on any of the pthread_cond_t words, otherwise it might interfere
-with the current operation of the structure. To solve this problem we
-used the left over word.
-
-If the stucture was initialized by a legacy Linuxthread
-PTHREAD_COND_INITIALIZER it contained a 1, and this indicates that the
-structure requires zeroing for NPTL. The first thread to come upon a
-pthread_cond_t with a 1 in the __initializer field, will
-compare-and-swap the value, placing a 2 there which will cause all other
-threads using the same pthread_cond_t to wait for the completion of the
-initialization. Lastly, we use a store (with memory barrier) to change
-__initializer from 2 to 0. Note that the store is strongly ordered, but
-we use the PA 1.1 compatible form which is ",ma" with zero offset.
-
-In the future, when the application is recompiled with NPTL
-PTHREAD_COND_INITIALIZER it will be a quick compare-and-swap, which
-fails because __initializer is zero, and the structure will be used as
-is correctly.  */
-
-#define cond_compat_clear(var) \
-({                                                                     \
-  int tmp = 0;                                                         \
-  var->__data.__wseq = 0;                                              \
-  var->__data.__signals_sent = 0;                                      \
-  var->__data.__confirmed = 0;                                         \
-  var->__data.__generation = 0;                                                \
-  var->__data.__mutex = NULL;                                          \
-  var->__data.__quiescence_waiters = 0;                                        \
-  var->__data.__clockid = 0;                                           \
-  /* Clear __initializer last, to indicate initialization is done.  */ \
-  /* This synchronizes-with the acquire load below.  */                        \
-  atomic_store_release (&var->__data.__initializer, 0);                        \
-})
-
-#define cond_compat_check_and_clear(var) \
-({                                                             \
-  int v;                                                       \
-  int *value = &var->__data.__initializer;                     \
-  /* This synchronizes-with the release store above.  */       \
-  while ((v = atomic_load_acquire (value)) != 0)               \
-    {                                                          \
-      if (v == 1                                               \
-         /* Relaxed MO is fine; it only matters who's first.  */        \
-         && atomic_compare_exchange_acquire_weak_relaxed (value, 1, 2)) \
-       {                                                       \
-         /* We're first; initialize structure.  */             \
-         cond_compat_clear (var);                              \
-         break;                                                \
-       }                                                       \
-      else                                                     \
-       /* Yield before we re-check initialization status.  */  \
-       sched_yield ();                                         \
-    }                                                          \
-})
-
-#endif
diff --git a/sysdeps/unix/sysv/linux/hppa/ipc_priv.h b/sysdeps/unix/sysv/linux/hppa/ipc_priv.h
new file mode 100644 (file)
index 0000000..d880f50
--- /dev/null
@@ -0,0 +1,21 @@
+/* Old SysV permission definition for Linux.  Hppa version.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <sys/ipc.h>  /* For __key_t  */
+
+#define __IPC_64       0x0
index 9dd81b47c81de54a02b96b395165c991682ec989..db9e24b0902096685e1f0c430022369ca3c9f456 100644 (file)
@@ -6,7 +6,6 @@ libc.so: free
 libc.so: malloc
 libc.so: memalign
 libc.so: realloc
-libc.so: _exit
 libc.so: __sigsetjmp
 libc.so: _IO_funlockfile
 libc.so: sigprocmask
index fc4573c86b2057962bc5e66d8b26d528af76f065..8b7d7df2fe8c27b6d49e5d64176f5da0c36a470c 100644 (file)
@@ -58,7 +58,10 @@ ENTRY(__vfork)
           that there is no child now, so it's safe to create
           a frame.  */
        stw     %rp, -20(%sp)
+       .cfi_offset 2, -20
        stwm    %r3, 64(%sp)
+       .cfi_def_cfa_offset -64
+       .cfi_offset 3, 0
        stw     %sp, -4(%sp)
 
        sub     %r0,%ret0,%r3
index ac617201d25da86b219a43c7afe1ba44a1b1a569..806072cde4291ef710dfdec6d0658fa1f60c06ea 100644 (file)
@@ -26,6 +26,7 @@
 #include <bits/pthreadtypes.h>
 #include <bits/setjmp.h>
 #include <bits/wordsize.h>
+#include <bits/types/struct_timespec.h>
 
 
 /* Detach state.  */
@@ -82,32 +83,18 @@ enum
 #endif
 
 
-#ifdef __PTHREAD_MUTEX_HAVE_PREV
-# define PTHREAD_MUTEX_INITIALIZER \
-  { { 0, 0, 0, 0, 0, __PTHREAD_SPINS, { 0, 0 } } }
-# ifdef __USE_GNU
-#  define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \
-  { { 0, 0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, __PTHREAD_SPINS, { 0, 0 } } }
-#  define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \
-  { { 0, 0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, __PTHREAD_SPINS, { 0, 0 } } }
-#  define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \
-  { { 0, 0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, __PTHREAD_SPINS, { 0, 0 } } }
-#  define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \
-  { { 0, 0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, __PTHREAD_SPINS, { 0, 0 } } }
-
-# endif
-#else
-# define PTHREAD_MUTEX_INITIALIZER \
-  { { 0, 0, 0, 0, 0, { __PTHREAD_SPINS } } }
-# ifdef __USE_GNU
-#  define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \
-  { { 0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, 0, { __PTHREAD_SPINS } } }
-#  define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \
-  { { 0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, 0, { __PTHREAD_SPINS } } }
-#  define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \
-  { { 0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, 0, { __PTHREAD_SPINS } } }
-
-# endif
+#define PTHREAD_MUTEX_INITIALIZER \
+  { { 0, 0, 0, 0, { 0, 0, 0, 0 }, 0, { __PTHREAD_SPINS }, 0, 0 } }
+#ifdef __USE_GNU
+# define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \
+  { { 0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, { 0, 0, 0, 0 }, 0, \
+      { __PTHREAD_SPINS }, 0, 0 } }
+# define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \
+  { { 0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, { 0, 0, 0, 0 }, 0, \
+      { __PTHREAD_SPINS }, 0, 0 } }
+# define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \
+  { { 0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, { 0, 0, 0, 0 }, 0, \
+      { __PTHREAD_SPINS }, 0, 0 } }
 #endif
 
 
@@ -130,25 +117,14 @@ enum
 # endif
 #endif
 
+
 /* Read-write lock initializers.  */
 # define PTHREAD_RWLOCK_INITIALIZER \
-  { { 0, 0, 0, 0, 0, 0, 0, 0, __PTHREAD_RWLOCK_ELISION_EXTRA, 0, 0 } }
+  { { { 0, 0, 0, 0 }, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }
 # ifdef __USE_GNU
-#  ifdef __PTHREAD_RWLOCK_INT_FLAGS_SHARED
-#   define PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP \
-  { { 0, 0, 0, 0, 0, 0, 0, 0, __PTHREAD_RWLOCK_ELISION_EXTRA, 0,                                             \
-       PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP } }
-#  else
-#   if __BYTE_ORDER == __LITTLE_ENDIAN
-#    define PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP \
-  { { 0, 0, 0, 0, 0, 0, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP, \
-      0, __PTHREAD_RWLOCK_ELISION_EXTRA, 0, 0 } }
-#   else
-#    define PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP \
-  { { 0, 0, 0, 0, 0, 0, 0, 0, 0, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP,\
-      0 } }
-#   endif
-#  endif
+#  define PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP \
+   { { { 0, 0, 0, 0 }, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
+       PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP, 0, 0, 0 } }
 # endif
 #endif  /* Unix98 or XOpen2K */
 
@@ -183,9 +159,8 @@ enum
 };
 
 
-
 /* Conditional variable handling.  */
-#define PTHREAD_COND_INITIALIZER { { 0, 0, 0, 0, 0, (void *) 0, 0, 0 } }
+#define PTHREAD_COND_INITIALIZER { { {0}, {0}, {0, 0}, {0, 0}, 0, 0, {0, 0} } }
 
 
 /* Cleanup buffers */
@@ -1161,43 +1136,3 @@ __NTH (pthread_equal (pthread_t __thread1, pthread_t __thread2))
 __END_DECLS
 
 #endif /* pthread.h */
-
-#ifndef _PTHREAD_H_HPPA_
-#define _PTHREAD_H_HPPA_ 1
-
-/* The pthread_cond_t initializer is compatible only with NPTL. We do not
-   want to be forwards compatible, we eventually want to drop the code
-   that has to clear the old LT initializer.  */
-#undef PTHREAD_COND_INITIALIZER
-#define PTHREAD_COND_INITIALIZER { { 0, 0, 0, (void *) 0, 0, 0, 0, 0, 0 } }
-
-/* The pthread_mutex_t and pthread_rwlock_t initializers are compatible
-   only with NPTL. NPTL assumes pthread_rwlock_t is all zero.  */
-#undef PTHREAD_MUTEX_INITIALIZER
-#undef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
-#undef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
-#undef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
-/* Mutex initializers.  */
-#define PTHREAD_MUTEX_INITIALIZER \
-  { { 0, 0, 0, 0, { 0, 0, 0, 0 }, 0, { 0 }, 0, 0 } }
-#ifdef __USE_GNU
-# define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \
-  { { 0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, { 0, 0, 0, 0 }, 0, { 0 }, 0, 0 } }
-# define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \
-  { { 0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, { 0, 0, 0, 0 }, 0, { 0 }, 0, 0 } }
-# define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \
-  { { 0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, { 0, 0, 0, 0 }, 0, { 0 }, 0, 0 } }
-#endif
-
-#undef PTHREAD_RWLOCK_INITIALIZER
-#undef PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP
-/* Read-write lock initializers.  */
-#define PTHREAD_RWLOCK_INITIALIZER \
-  { { { 0, 0, 0, 0 }, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }
-#ifdef __USE_GNU
-# define PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP \
-  { { { 0, 0, 0, 0 }, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP,\
-      0, 0, 0 } }
-#endif  /* Unix98 or XOpen2K */
-
-#endif
diff --git a/sysdeps/unix/sysv/linux/hppa/pthread_cond_broadcast.c b/sysdeps/unix/sysv/linux/hppa/pthread_cond_broadcast.c
deleted file mode 100644 (file)
index a6f9f5d..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/* Copyright (C) 2009-2017 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Carlos O'Donell <carlos@codesourcery.com>, 2009.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library.  If not, see
-   <http://www.gnu.org/licenses/>.  */
-
-#ifndef INCLUDED_SELF
-# define INCLUDED_SELF
-# include <pthread_cond_broadcast.c>
-#else
-# include <pthread.h>
-# include <pthreadP.h>
-# include <internaltypes.h>
-# include <shlib-compat.h>
-int
-__pthread_cond_broadcast (pthread_cond_t *cond)
-{
-  cond_compat_check_and_clear (cond);
-  return __pthread_cond_broadcast_internal (cond);
-}
-versioned_symbol (libpthread, __pthread_cond_broadcast, pthread_cond_broadcast,
-                  GLIBC_2_3_2);
-# undef versioned_symbol
-# define versioned_symbol(lib, local, symbol, version)
-# undef __pthread_cond_broadcast
-# define __pthread_cond_broadcast __pthread_cond_broadcast_internal
-# include_next <pthread_cond_broadcast.c>
-#endif
diff --git a/sysdeps/unix/sysv/linux/hppa/pthread_cond_destroy.c b/sysdeps/unix/sysv/linux/hppa/pthread_cond_destroy.c
deleted file mode 100644 (file)
index 49af087..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/* Copyright (C) 2009-2017 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Carlos O'Donell <carlos@codesourcery.com>, 2009.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library.  If not, see
-   <http://www.gnu.org/licenses/>.  */
-
-#ifndef INCLUDED_SELF
-# define INCLUDED_SELF
-# include <pthread_cond_destroy.c>
-#else
-# include <pthread.h>
-# include <pthreadP.h>
-# include <internaltypes.h>
-# include <shlib-compat.h>
-int
-__pthread_cond_destroy (pthread_cond_t *cond)
-{
-  cond_compat_check_and_clear (cond);
-  return __pthread_cond_destroy_internal (cond);
-}
-versioned_symbol (libpthread, __pthread_cond_destroy, pthread_cond_destroy,
-                  GLIBC_2_3_2);
-# undef versioned_symbol
-# define versioned_symbol(lib, local, symbol, version)
-# undef __pthread_cond_destroy
-# define __pthread_cond_destroy __pthread_cond_destroy_internal
-# include_next <pthread_cond_destroy.c>
-#endif
diff --git a/sysdeps/unix/sysv/linux/hppa/pthread_cond_init.c b/sysdeps/unix/sysv/linux/hppa/pthread_cond_init.c
deleted file mode 100644 (file)
index ccb3de0..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/* Copyright (C) 2009-2017 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Carlos O'Donell <carlos@codesourcery.com>, 2009.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library.  If not, see
-   <http://www.gnu.org/licenses/>.  */
-
-#ifndef INCLUDED_SELF
-# define INCLUDED_SELF
-# include <pthread_cond_init.c>
-#else
-# include <pthread.h>
-# include <pthreadP.h>
-# include <internaltypes.h>
-# include <shlib-compat.h>
-int
-__pthread_cond_init (pthread_cond_t *cond, const pthread_condattr_t *cond_attr)
-{
-  cond_compat_clear (cond);
-  return __pthread_cond_init_internal (cond, cond_attr);
-}
-versioned_symbol (libpthread, __pthread_cond_init, pthread_cond_init,
-                  GLIBC_2_3_2);
-# undef versioned_symbol
-# define versioned_symbol(lib, local, symbol, version)
-# undef __pthread_cond_init
-# define __pthread_cond_init __pthread_cond_init_internal
-# include_next <pthread_cond_init.c>
-#endif
diff --git a/sysdeps/unix/sysv/linux/hppa/pthread_cond_signal.c b/sysdeps/unix/sysv/linux/hppa/pthread_cond_signal.c
deleted file mode 100644 (file)
index 2bf32af..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/* Copyright (C) 2009-2017 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Carlos O'Donell <carlos@codesourcery.com>, 2009.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library.  If not, see
-   <http://www.gnu.org/licenses/>.  */
-
-#ifndef INCLUDED_SELF
-# define INCLUDED_SELF
-# include <pthread_cond_signal.c>
-#else
-# include <pthread.h>
-# include <pthreadP.h>
-# include <internaltypes.h>
-# include <shlib-compat.h>
-int
-__pthread_cond_signal (pthread_cond_t *cond)
-{
-  cond_compat_check_and_clear (cond);
-  return __pthread_cond_signal_internal (cond);
-}
-versioned_symbol (libpthread, __pthread_cond_signal, pthread_cond_signal,
-                  GLIBC_2_3_2);
-# undef versioned_symbol
-# define versioned_symbol(lib, local, symbol, version)
-# undef __pthread_cond_signal
-# define __pthread_cond_signal __pthread_cond_signal_internal
-# include_next <pthread_cond_signal.c>
-#endif
diff --git a/sysdeps/unix/sysv/linux/hppa/pthread_cond_wait.c b/sysdeps/unix/sysv/linux/hppa/pthread_cond_wait.c
deleted file mode 100644 (file)
index 1cc2fc1..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/* Copyright (C) 2009-2017 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Carlos O'Donell <carlos@codesourcery.com>, 2009.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library.  If not, see
-   <http://www.gnu.org/licenses/>.  */
-
-#ifndef INCLUDED_SELF
-# define INCLUDED_SELF
-# include <pthread_cond_wait.c>
-#else
-# include <pthread.h>
-# include <pthreadP.h>
-# include <internaltypes.h>
-# include <shlib-compat.h>
-int
-__pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)
-{
-  cond_compat_check_and_clear (cond);
-  return __pthread_cond_wait_internal (cond, mutex);
-}
-versioned_symbol (libpthread, __pthread_cond_wait, pthread_cond_wait,
-                  GLIBC_2_3_2);
-int
-__pthread_cond_timedwait (cond, mutex, abstime)
-     pthread_cond_t *cond;
-     pthread_mutex_t *mutex;
-     const struct timespec *abstime;
-{
-  cond_compat_check_and_clear (cond);
-  return __pthread_cond_timedwait_internal (cond, mutex, abstime);
-}
-versioned_symbol (libpthread, __pthread_cond_timedwait, pthread_cond_timedwait,
-                  GLIBC_2_3_2);
-# undef versioned_symbol
-# define versioned_symbol(lib, local, symbol, version)
-# undef __pthread_cond_wait
-# define __pthread_cond_wait __pthread_cond_wait_internal
-# undef __pthread_cond_timedwait
-# define __pthread_cond_timedwait __pthread_cond_timedwait_internal
-# include_next <pthread_cond_wait.c>
-#endif
index 3f4da7938fdc1140be87455a0585d5672448de5f..92cb204f8d6275e1109197b7aef82a9e4805a101 100644 (file)
 ENTRY(__setcontext)
        /* Prologue */
        stwm    %r3, 64(%sp)
+       .cfi_def_cfa_offset -64
+       .cfi_offset 3, 0
 #ifdef PIC
        stw     %r19, -32(%sp)
+       .cfi_offset 19, 32
 #endif
 
        /* Save ucp.  */
@@ -141,7 +144,7 @@ ENTRY(__setcontext)
 
        /* No further context available. Exit now.  */
        bl      HIDDEN_JUMPTARGET(exit), %r2
-       ldi     -1, %r26
+       ldi     0, %r26
 
 
 .Lerror:
index 5ea297267ff6b8a59aac912ea040807dd7e8b8c8..8b7f2b20951b7bddd08aa8cd9b1808928f51f6ac 100644 (file)
        ENTRY (__##syscall_name##_nocancel)                             \
        DOARGS_##args                                   ASM_LINE_SEP    \
        stwm TREG, 64(%sp)                              ASM_LINE_SEP    \
+       .cfi_def_cfa_offset -64                         ASM_LINE_SEP    \
        .cfi_offset TREG, 0                             ASM_LINE_SEP    \
-       .cfi_adjust_cfa_offset 64                       ASM_LINE_SEP    \
        stw %sp, -4(%sp)                                ASM_LINE_SEP    \
-       .cfi_offset 30, -4                              ASM_LINE_SEP    \
        stw %r19, -32(%sp)                              ASM_LINE_SEP    \
-       .cfi_offset 19, -32                             ASM_LINE_SEP    \
+       .cfi_offset 19, 32                              ASM_LINE_SEP    \
        /* Save r19 */                                  ASM_LINE_SEP    \
        SAVE_PIC(TREG)                                  ASM_LINE_SEP    \
        /* Do syscall, delay loads # */                 ASM_LINE_SEP    \
@@ -91,21 +90,19 @@ L(pre_nc_end):                                              ASM_LINE_SEP    \
        /* No need to LOAD_PIC */                       ASM_LINE_SEP    \
        /* Undo frame */                                ASM_LINE_SEP    \
        ldwm -64(%sp),TREG                              ASM_LINE_SEP    \
-       .cfi_adjust_cfa_offset -64                      ASM_LINE_SEP    \
        /* Restore rp before exit */                    ASM_LINE_SEP    \
        ldw -20(%sp), %rp                               ASM_LINE_SEP    \
-       .cfi_restore 2                                  ASM_LINE_SEP    \
        ret                                             ASM_LINE_SEP    \
        END(__##syscall_name##_nocancel)                ASM_LINE_SEP    \
        /**********************************************/ASM_LINE_SEP    \
        ENTRY (name)                                                    \
        DOARGS_##args                                   ASM_LINE_SEP    \
        stwm TREG, 64(%sp)                              ASM_LINE_SEP    \
-       .cfi_adjust_cfa_offset 64                       ASM_LINE_SEP    \
+       .cfi_def_cfa_offset -64                         ASM_LINE_SEP    \
+       .cfi_offset TREG, 0                             ASM_LINE_SEP    \
        stw %sp, -4(%sp)                                ASM_LINE_SEP    \
-       .cfi_offset 30, -4                              ASM_LINE_SEP    \
        stw %r19, -32(%sp)                              ASM_LINE_SEP    \
-       .cfi_offset 19, -32                             ASM_LINE_SEP    \
+       .cfi_offset 19, 32                              ASM_LINE_SEP    \
        /* Done setting up frame, continue... */        ASM_LINE_SEP    \
        SINGLE_THREAD_P                                 ASM_LINE_SEP    \
        cmpib,<>,n 0,%ret0,L(pseudo_cancel)             ASM_LINE_SEP    \
@@ -168,40 +165,32 @@ L(pre_end):                                               ASM_LINE_SEP    \
        /* No need to LOAD_PIC */                       ASM_LINE_SEP    \
        /* Undo frame */                                ASM_LINE_SEP    \
        ldwm -64(%sp),TREG                              ASM_LINE_SEP    \
-       .cfi_adjust_cfa_offset -64                      ASM_LINE_SEP    \
        /* Restore rp before exit */                    ASM_LINE_SEP    \
-       ldw -20(%sp), %rp                               ASM_LINE_SEP    \
-       .cfi_restore 2                                  ASM_LINE_SEP
+       ldw -20(%sp), %rp                               ASM_LINE_SEP
 
 /* Save arguments into our frame */
 # define PUSHARGS_0    /* nothing to do */
 # define PUSHARGS_1    PUSHARGS_0 stw %r26, -36(%sr0,%sp)      ASM_LINE_SEP    \
-                       .cfi_offset 26, -36                     ASM_LINE_SEP
+                       .cfi_offset 26, 28                      ASM_LINE_SEP
 # define PUSHARGS_2    PUSHARGS_1 stw %r25, -40(%sr0,%sp)      ASM_LINE_SEP    \
-                       .cfi_offset 25, -40                     ASM_LINE_SEP
+                       .cfi_offset 25, 24                      ASM_LINE_SEP
 # define PUSHARGS_3    PUSHARGS_2 stw %r24, -44(%sr0,%sp)      ASM_LINE_SEP    \
-                       .cfi_offset 24, -44                     ASM_LINE_SEP
+                       .cfi_offset 24, 20                      ASM_LINE_SEP
 # define PUSHARGS_4    PUSHARGS_3 stw %r23, -48(%sr0,%sp)      ASM_LINE_SEP    \
-                       .cfi_offset 23, -48                     ASM_LINE_SEP
+                       .cfi_offset 23, 16                      ASM_LINE_SEP
 # define PUSHARGS_5    PUSHARGS_4 stw %r22, -52(%sr0,%sp)      ASM_LINE_SEP    \
-                       .cfi_offset 22, -52                     ASM_LINE_SEP
+                       .cfi_offset 22, 12                      ASM_LINE_SEP
 # define PUSHARGS_6    PUSHARGS_5 stw %r21, -56(%sr0,%sp)      ASM_LINE_SEP    \
-                       .cfi_offset 21, -56                     ASM_LINE_SEP
+                       .cfi_offset 21, 8                       ASM_LINE_SEP
 
 /* Bring them back from the stack */
 # define POPARGS_0     /* nothing to do */
-# define POPARGS_1     POPARGS_0 ldw -36(%sr0,%sp), %r26       ASM_LINE_SEP    \
-                       .cfi_restore 26                         ASM_LINE_SEP
-# define POPARGS_2     POPARGS_1 ldw -40(%sr0,%sp), %r25       ASM_LINE_SEP    \
-                       .cfi_restore 25                         ASM_LINE_SEP
-# define POPARGS_3     POPARGS_2 ldw -44(%sr0,%sp), %r24       ASM_LINE_SEP    \
-                       .cfi_restore 24                         ASM_LINE_SEP
-# define POPARGS_4     POPARGS_3 ldw -48(%sr0,%sp), %r23       ASM_LINE_SEP    \
-                       .cfi_restore 23                         ASM_LINE_SEP
-# define POPARGS_5     POPARGS_4 ldw -52(%sr0,%sp), %r22       ASM_LINE_SEP    \
-                       .cfi_restore 22                         ASM_LINE_SEP
-# define POPARGS_6     POPARGS_5 ldw -56(%sr0,%sp), %r21       ASM_LINE_SEP    \
-                       .cfi_restore 21                         ASM_LINE_SEP
+# define POPARGS_1     POPARGS_0 ldw -36(%sr0,%sp), %r26       ASM_LINE_SEP
+# define POPARGS_2     POPARGS_1 ldw -40(%sr0,%sp), %r25       ASM_LINE_SEP
+# define POPARGS_3     POPARGS_2 ldw -44(%sr0,%sp), %r24       ASM_LINE_SEP
+# define POPARGS_4     POPARGS_3 ldw -48(%sr0,%sp), %r23       ASM_LINE_SEP
+# define POPARGS_5     POPARGS_4 ldw -52(%sr0,%sp), %r22       ASM_LINE_SEP
+# define POPARGS_6     POPARGS_5 ldw -56(%sr0,%sp), %r21       ASM_LINE_SEP
 
 # if IS_IN (libpthread)
 #  ifdef PIC
index d8dd0431a45161ebe7107041ac371a76845d09af..c0cd59e9f549dbe51c5feb3a9785e556a049df5d 100644 (file)
    to another function */
 #define TREG 4
 #define SAVE_PIC(SREG) \
-       copy %r19, SREG ASM_LINE_SEP    \
-       .cfi_register 19, SREG
+       copy %r19, SREG
 #define LOAD_PIC(LREG) \
-       copy LREG , %r19 ASM_LINE_SEP   \
-       .cfi_restore 19
+       copy LREG , %r19
 /* Inline assembly defines */
 #define TREG_ASM "%r4" /* Cant clobber r3, it holds framemarker */
 #define SAVE_ASM_PIC   "       copy %%r19, %" TREG_ASM "\n"
 #define DO_CALL(syscall_name, args)                            \
        /* Create a frame */                    ASM_LINE_SEP    \
        stwm TREG, 64(%sp)                      ASM_LINE_SEP    \
+       .cfi_def_cfa_offset -64                 ASM_LINE_SEP    \
        .cfi_offset TREG, 0                     ASM_LINE_SEP    \
-       .cfi_adjust_cfa_offset 64               ASM_LINE_SEP    \
        stw %sp, -4(%sp)                        ASM_LINE_SEP    \
-       .cfi_offset 30, -4                      ASM_LINE_SEP    \
        stw %r19, -32(%sp)                      ASM_LINE_SEP    \
-       .cfi_offset 19, -32                     ASM_LINE_SEP    \
+       .cfi_offset 19, 32                      ASM_LINE_SEP    \
        /* Save r19 */                          ASM_LINE_SEP    \
        SAVE_PIC(TREG)                          ASM_LINE_SEP    \
        /* Do syscall, delay loads # */         ASM_LINE_SEP    \
 L(pre_end):                                    ASM_LINE_SEP    \
        /* Restore our frame, restoring TREG */ ASM_LINE_SEP    \
        ldwm -64(%sp), TREG                     ASM_LINE_SEP    \
-       .cfi_adjust_cfa_offset -64              ASM_LINE_SEP    \
        /* Restore return pointer */            ASM_LINE_SEP    \
-       ldw -20(%sp),%rp                        ASM_LINE_SEP    \
-       .cfi_restore 2                          ASM_LINE_SEP
+       ldw -20(%sp),%rp                        ASM_LINE_SEP
 
 /* We do nothing with the return, except hand it back to someone else */
 #undef  DO_CALL_NOERRNO
index f68195137ebbe20bfe84e78362bf9159bb1bbaa1..230f9fc037f583a3bb045d2308bd259f17663b47 100644 (file)
@@ -19,6 +19,7 @@
 #include <dirent.h>
 #include <glob.h>
 #include <sys/stat.h>
+#include <shlib-compat.h>
 
 #define dirent dirent64
 #define __readdir(dirp) __readdir64 (dirp)
 #undef __stat
 #define __stat(file, buf) __xstat64 (_STAT_VER, file, buf)
 
-#define NO_GLOB_PATTERN_P 1
-
 #define COMPILE_GLOB64 1
 
 #include <posix/glob.c>
 
-#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 <sysdeps/unix/sysv/linux/i386/olddirent.h>
-
-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 <posix/glob.c>
-
-compat_symbol (libc, __old_glob64, glob64, GLIBC_2_1);
-#endif
index 2c2584956d038a4b64e56731378f12b96fb7b304..8ea4333846df29ac63d28f76ff351e749fcf6a3f 100644 (file)
@@ -6,7 +6,7 @@ libc.so: free + REL R_386_GLOB_DAT
 libc.so: malloc + REL R_386_GLOB_DAT
 libc.so: memalign + REL R_386_GLOB_DAT
 libc.so: realloc + REL R_386_GLOB_DAT
-libm.so: matherr
+libm.so: matherr + REL R_386_GLOB_DAT
 # The main malloc is interposed into the dynamic linker, for
 # allocations after the initial link (when dlopen is used).
 ld.so: malloc + REL R_386_GLOB_DAT
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/globfree64.c b/sysdeps/unix/sysv/linux/mips/mips64/n64/globfree64.c
new file mode 100644 (file)
index 0000000..abc35fd
--- /dev/null
@@ -0,0 +1 @@
+/* glob64 is in globfree64.c */
index 9776ee96e547d3b819b452aa36682e00687687d7..5a6379613bc0e9b9b6204cb117a181c5958b6154 100644 (file)
@@ -29,5 +29,7 @@
 _strong_alias (__posix_fadvise64_l64, __posix_fadvise64_l32);
 compat_symbol (libc, __posix_fadvise64_l32, posix_fadvise64, GLIBC_2_2);
 versioned_symbol (libc, __posix_fadvise64_l64, posix_fadvise64, GLIBC_2_3_3);
+#else
+_weak_alias (posix_fadvise, posix_fadvise64);
 #endif
 _strong_alias (__posix_fadvise64_l64, posix_fadvise);
diff --git a/sysdeps/unix/sysv/linux/oldglob.c b/sysdeps/unix/sysv/linux/oldglob.c
new file mode 100644 (file)
index 0000000..8233e57
--- /dev/null
@@ -0,0 +1,42 @@
+#include <shlib-compat.h>
+
+#if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2)
+
+#include <dirent.h>
+#include <glob.h>
+#include <sys/stat.h>
+
+#include <sysdeps/unix/sysv/linux/i386/olddirent.h>
+
+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 <posix/glob.c>
+
+libc_hidden_def (__old_glob64);
+
+compat_symbol (libc, __old_glob64, glob64, GLIBC_2_1);
+#endif
index d324237edd469c149f4595b95e484f924b6c1bc6..0221ac2cf5eaa2ea67cf448799afd3e8e4b16210 100644 (file)
@@ -26,8 +26,8 @@
 /* In glibc release 2.19 new versions of longjmp-functions were introduced,
    but were reverted before 2.20. Thus both versions are the same function.  */
 
-strong_alias (longjmp_ifunc, __v2longjmp)
+strong_alias (longjmp_alias, __v2longjmp)
 compat_symbol (libpthread, __v2longjmp, longjmp, GLIBC_2_19);
-strong_alias (siglongjmp_ifunc, __v2siglongjmp)
+strong_alias (siglongjmp_alias, __v2siglongjmp)
 compat_symbol (libpthread, __v2siglongjmp, siglongjmp, GLIBC_2_19);
 #endif /* SHLIB_COMPAT (libpthread, GLIBC_2_19, GLIBC_2_20))  */
diff --git a/sysdeps/unix/sysv/linux/sparc/bits/long-double.h b/sysdeps/unix/sysv/linux/sparc/bits/long-double.h
deleted file mode 100644 (file)
index 094e051..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/* Properties of long double type.  SPARC version.
-   Copyright (C) 2016-2017 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License  published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <http://www.gnu.org/licenses/>.  */
-
-#include <bits/wordsize.h>
-
-#if !defined __NO_LONG_DOUBLE_MATH && __WORDSIZE == 32
-# define __LONG_DOUBLE_MATH_OPTIONAL   1
-# ifndef __LONG_DOUBLE_128__
-#  define __NO_LONG_DOUBLE_MATH        1
-# endif
-#endif
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/bits/long-double.h b/sysdeps/unix/sysv/linux/sparc/sparc32/bits/long-double.h
new file mode 100644 (file)
index 0000000..094e051
--- /dev/null
@@ -0,0 +1,26 @@
+/* Properties of long double type.  SPARC version.
+   Copyright (C) 2016-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License  published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <bits/wordsize.h>
+
+#if !defined __NO_LONG_DOUBLE_MATH && __WORDSIZE == 32
+# define __LONG_DOUBLE_MATH_OPTIONAL   1
+# ifndef __LONG_DOUBLE_128__
+#  define __NO_LONG_DOUBLE_MATH        1
+# endif
+#endif
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/bits/long-double.h b/sysdeps/unix/sysv/linux/sparc/sparc64/bits/long-double.h
new file mode 100644 (file)
index 0000000..094e051
--- /dev/null
@@ -0,0 +1,26 @@
+/* Properties of long double type.  SPARC version.
+   Copyright (C) 2016-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License  published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <bits/wordsize.h>
+
+#if !defined __NO_LONG_DOUBLE_MATH && __WORDSIZE == 32
+# define __LONG_DOUBLE_MATH_OPTIONAL   1
+# ifndef __LONG_DOUBLE_128__
+#  define __NO_LONG_DOUBLE_MATH        1
+# endif
+#endif
index 2daf0c5ef040032aac015dee9f86028c3d2a58ee..ee09fb762b2d108d6c9854bdd8d6280c34eb4175 100644 (file)
@@ -17,7 +17,6 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <spawn.h>
-#include <assert.h>
 #include <fcntl.h>
 #include <paths.h>
 #include <string.h>
 #define SPAWN_ERROR    127
 
 #ifdef __ia64__
-# define CLONE(__fn, __stack, __stacksize, __flags, __args) \
-  __clone2 (__fn, __stack, __stacksize, __flags, __args, 0, 0, 0)
+# define CLONE(__fn, __stackbase, __stacksize, __flags, __args) \
+  __clone2 (__fn, __stackbase, __stacksize, __flags, __args, 0, 0, 0)
 #else
 # define CLONE(__fn, __stack, __stacksize, __flags, __args) \
   __clone (__fn, __stack, __flags, __args)
 #endif
 
-#if _STACK_GROWS_DOWN
-# define STACK(__stack, __stack_size) (__stack + __stack_size)
-#elif _STACK_GROWS_UP
+/* Since ia64 wants the stackbase w/clone2, re-use the grows-up macro.  */
+#if _STACK_GROWS_UP || defined (__ia64__)
 # define STACK(__stack, __stack_size) (__stack)
+#elif _STACK_GROWS_DOWN
+# define STACK(__stack, __stack_size) (__stack + __stack_size)
 #endif
 
 
@@ -265,7 +265,6 @@ __spawni_child (void *arguments)
   __sigprocmask (SIG_SETMASK, (attr->__flags & POSIX_SPAWN_SETSIGMASK)
                 ? &attr->__ss : &args->oldmask, 0);
 
-  args->err = 0;
   args->exec (args->file, args->argv, args->envp);
 
   /* This is compatibility function required to enable posix_spawn run
@@ -318,6 +317,11 @@ __spawnix (pid_t * pid, const char *file,
 
   /* Add a slack area for child's stack.  */
   size_t argv_size = (argc * sizeof (void *)) + 512;
+  /* We need at least a few pages in case the compiler's stack checking is
+     enabled.  In some configs, it is known to use at least 24KiB.  We use
+     32KiB to be "safe" from anything the compiler might do.  Besides, the
+     extra pages won't actually be allocated unless they get used.  */
+  argv_size += (32 * 1024);
   size_t stack_size = ALIGN_UP (argv_size, GLRO(dl_pagesize));
   void *stack = __mmap (NULL, stack_size, prot,
                        MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
@@ -331,7 +335,7 @@ __spawnix (pid_t * pid, const char *file,
 
   /* Child must set args.err to something non-negative - we rely on
      the parent and child sharing VM.  */
-  args.err = -1;
+  args.err = 0;
   args.file = file;
   args.exec = exec;
   args.fa = file_actions;
@@ -354,12 +358,26 @@ __spawnix (pid_t * pid, const char *file,
   new_pid = CLONE (__spawni_child, STACK (stack, stack_size), stack_size,
                   CLONE_VM | CLONE_VFORK | SIGCHLD, &args);
 
+  /* It needs to collect the case where the auxiliary process was created
+     but failed to execute the file (due either any preparation step or
+     for execve itself).  */
   if (new_pid > 0)
     {
+      /* Also, it handles the unlikely case where the auxiliary process was
+        terminated before calling execve as if it was successfully.  The
+        args.err is set to 0 as default and changed to a positive value
+        only in case of failure, so in case of premature termination
+        due a signal args.err will remain zeroed and it will be up to
+        caller to actually collect it.  */
       ec = args.err;
-      assert (ec >= 0);
-      if (ec != 0)
-         __waitpid (new_pid, NULL, 0);
+      if (ec > 0)
+       /* There still an unlikely case where the child is cancelled after
+          setting args.err, due to a positive error value.  Also there is
+          possible pid reuse race (where the kernel allocated the same pid
+          to an unrelated process).  Unfortunately due synchronization
+          issues where the kernel might not have the process collected
+          the waitpid below can not use WNOHANG.  */
+       __waitpid (new_pid, NULL, 0);
     }
   else
     ec = -new_pid;
diff --git a/sysdeps/unix/sysv/linux/wordsize-64/globfree64.c b/sysdeps/unix/sysv/linux/wordsize-64/globfree64.c
new file mode 100644 (file)
index 0000000..af035e1
--- /dev/null
@@ -0,0 +1,2 @@
+/* This file is here so sysdeps/gnu/glob64.c doesn't take precedence.  */
+#include <sysdeps/wordsize-64/globfree64.c>
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 (file)
index 0000000..b76a761
--- /dev/null
@@ -0,0 +1 @@
+#include <sysdeps/wordsize-64/globfree.c>
index 082faf1c70b5070597d4d1834b03aa94e7b8e32d..954e8d37e279dccdc180e77ef8541ab712435144 100644 (file)
@@ -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 (file)
index 0000000..ec8c35b
--- /dev/null
@@ -0,0 +1,5 @@
+#define globfree64 __no_globfree64_decl
+#include <posix/globfree.c>
+#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 (file)
index 0000000..a0f57ff
--- /dev/null
@@ -0,0 +1 @@
+/* globfree64 is in globfree.c */
index f6739fae8173721b73a3f160817a42dbf12da3f3..33dd094e37f0fec723538429685e4a1441ec9e28 100644 (file)
@@ -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)
 
index 1c714a4017b5db9228a35401b1561e72efc693ce..38012912be6d32ba3003462d42cc0228a1ee855a 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <cpuid.h>
 #include <cpu-features.h>
+#include <libc-internal.h>
 
 static void
 get_common_indeces (struct cpu_features *cpu_features,
@@ -93,6 +94,71 @@ get_common_indeces (struct cpu_features *cpu_features,
                }
            }
        }
+
+      /* For _dl_runtime_resolve, set xsave_state_size to xsave area
+        size + integer register save size and align it to 64 bytes.  */
+      if (cpu_features->max_cpuid >= 0xd)
+       {
+         unsigned int eax, ebx, ecx, edx;
+
+         __cpuid_count (0xd, 0, eax, ebx, ecx, edx);
+         if (ebx != 0)
+           {
+             cpu_features->xsave_state_size
+               = ALIGN_UP (ebx + STATE_SAVE_OFFSET, 64);
+
+             __cpuid_count (0xd, 1, eax, ebx, ecx, edx);
+
+             /* Check if XSAVEC is available.  */
+             if ((eax & (1 << 1)) != 0)
+               {
+                 unsigned int xstate_comp_offsets[32];
+                 unsigned int xstate_comp_sizes[32];
+                 unsigned int i;
+
+                 xstate_comp_offsets[0] = 0;
+                 xstate_comp_offsets[1] = 160;
+                 xstate_comp_offsets[2] = 576;
+                 xstate_comp_sizes[0] = 160;
+                 xstate_comp_sizes[1] = 256;
+
+                 for (i = 2; i < 32; i++)
+                   {
+                     if ((STATE_SAVE_MASK & (1 << i)) != 0)
+                       {
+                         __cpuid_count (0xd, i, eax, ebx, ecx, edx);
+                         xstate_comp_sizes[i] = eax;
+                       }
+                     else
+                       {
+                         ecx = 0;
+                         xstate_comp_sizes[i] = 0;
+                       }
+
+                     if (i > 2)
+                       {
+                         xstate_comp_offsets[i]
+                           = (xstate_comp_offsets[i - 1]
+                              + xstate_comp_sizes[i -1]);
+                         if ((ecx & (1 << 1)) != 0)
+                           xstate_comp_offsets[i]
+                             = ALIGN_UP (xstate_comp_offsets[i], 64);
+                       }
+                   }
+
+                 /* Use XSAVEC.  */
+                 unsigned int size
+                   = xstate_comp_offsets[31] + xstate_comp_sizes[31];
+                 if (size)
+                   {
+                     cpu_features->xsave_state_size
+                       = ALIGN_UP (size + STATE_SAVE_OFFSET, 64);
+                     cpu_features->feature[index_arch_XSAVEC_Usable]
+                       |= bit_arch_XSAVEC_Usable;
+                   }
+               }
+           }
+       }
     }
 }
 
@@ -139,8 +205,6 @@ init_cpu_features (struct cpu_features *cpu_features)
 
            case 0x57:
              /* Knights Landing.  Enable Silvermont optimizations.  */
-             cpu_features->feature[index_arch_Prefer_No_VZEROUPPER]
-               |= bit_arch_Prefer_No_VZEROUPPER;
 
            case 0x5c:
            case 0x5f:
@@ -226,19 +290,15 @@ init_cpu_features (struct cpu_features *cpu_features)
        cpu_features->feature[index_arch_AVX_Fast_Unaligned_Load]
          |= bit_arch_AVX_Fast_Unaligned_Load;
 
-      /* To avoid SSE transition penalty, use _dl_runtime_resolve_slow.
-         If XGETBV suports ECX == 1, use _dl_runtime_resolve_opt.  */
-      cpu_features->feature[index_arch_Use_dl_runtime_resolve_slow]
-       |= bit_arch_Use_dl_runtime_resolve_slow;
-      if (cpu_features->max_cpuid >= 0xd)
-       {
-         unsigned int eax;
-
-         __cpuid_count (0xd, 1, eax, ebx, ecx, edx);
-         if ((eax & (1 << 2)) != 0)
-           cpu_features->feature[index_arch_Use_dl_runtime_resolve_opt]
-             |= bit_arch_Use_dl_runtime_resolve_opt;
-       }
+      /* Since AVX512ER is unique to Xeon Phi, set Prefer_No_VZEROUPPER
+         if AVX512ER is available.  Don't use AVX512 to avoid lower CPU
+        frequency if AVX512ER isn't available.  */
+      if (CPU_FEATURES_CPU_P (cpu_features, AVX512ER))
+       cpu_features->feature[index_arch_Prefer_No_VZEROUPPER]
+         |= bit_arch_Prefer_No_VZEROUPPER;
+      else
+       cpu_features->feature[index_arch_Prefer_No_AVX512]
+         |= bit_arch_Prefer_No_AVX512;
     }
   /* This spells out "AuthenticAMD".  */
   else if (ebx == 0x68747541 && ecx == 0x444d4163 && edx == 0x69746e65)
index 95f0fcff87cb505593b8f5094947e5c024f3b5e8..af83a28512d2889bc8b06b280a0ebf1a11fb0bef 100644 (file)
@@ -37,8 +37,8 @@
 #define bit_arch_Prefer_No_VZEROUPPER          (1 << 17)
 #define bit_arch_Fast_Unaligned_Copy           (1 << 18)
 #define bit_arch_Prefer_ERMS                   (1 << 19)
-#define bit_arch_Use_dl_runtime_resolve_opt    (1 << 20)
-#define bit_arch_Use_dl_runtime_resolve_slow   (1 << 21)
+#define bit_arch_Prefer_No_AVX512              (1 << 20)
+#define bit_arch_XSAVEC_Usable                 (1 << 21)
 
 /* CPUID Feature flags.  */
 
 #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)
 /* 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 <cpu-features-offsets.h>
 # define index_arch_Prefer_ERMS                FEATURE_INDEX_1*FEATURE_SIZE
 # define index_arch_Use_dl_runtime_resolve_opt FEATURE_INDEX_1*FEATURE_SIZE
 # define index_arch_Use_dl_runtime_resolve_slow FEATURE_INDEX_1*FEATURE_SIZE
+# define index_arch_Prefer_No_AVX512   FEATURE_INDEX_1*FEATURE_SIZE
 
 
 # if defined (_LIBC) && !IS_IN (nonlib)
@@ -199,6 +214,12 @@ struct cpu_features
   } cpuid[COMMON_CPUID_INDEX_MAX];
   unsigned int family;
   unsigned int model;
+  /* The type must be unsigned long int so that we use
+
+       sub xsave_state_size_offset(%rip) %RSP_LP
+
+     in _dl_runtime_resolve.  */
+  unsigned long int xsave_state_size;
   unsigned int feature[FEATURE_INDEX_MAX];
 };
 
@@ -236,6 +257,11 @@ extern const struct cpu_features *__get_cpu_features (void)
 # define index_cpu_AVX2                COMMON_CPUID_INDEX_7
 # define index_cpu_AVX512F     COMMON_CPUID_INDEX_7
 # define index_cpu_AVX512DQ    COMMON_CPUID_INDEX_7
+# define index_cpu_AVX512PF    COMMON_CPUID_INDEX_7
+# define index_cpu_AVX512ER    COMMON_CPUID_INDEX_7
+# define index_cpu_AVX512CD    COMMON_CPUID_INDEX_7
+# define index_cpu_AVX512BW    COMMON_CPUID_INDEX_7
+# define index_cpu_AVX512VL    COMMON_CPUID_INDEX_7
 # define index_cpu_ERMS                COMMON_CPUID_INDEX_7
 # define index_cpu_RTM         COMMON_CPUID_INDEX_7
 # define index_cpu_FMA         COMMON_CPUID_INDEX_1
@@ -254,6 +280,11 @@ extern const struct cpu_features *__get_cpu_features (void)
 # define reg_AVX2              ebx
 # define reg_AVX512F           ebx
 # define reg_AVX512DQ          ebx
+# define reg_AVX512PF          ebx
+# define reg_AVX512ER          ebx
+# define reg_AVX512CD          ebx
+# define reg_AVX512BW          ebx
+# define reg_AVX512VL          ebx
 # define reg_ERMS              ebx
 # define reg_RTM               ebx
 # define reg_FMA               ecx
@@ -281,8 +312,8 @@ extern const struct cpu_features *__get_cpu_features (void)
 # define index_arch_Prefer_No_VZEROUPPER FEATURE_INDEX_1
 # define index_arch_Fast_Unaligned_Copy        FEATURE_INDEX_1
 # define index_arch_Prefer_ERMS                FEATURE_INDEX_1
-# define index_arch_Use_dl_runtime_resolve_opt FEATURE_INDEX_1
-# define index_arch_Use_dl_runtime_resolve_slow FEATURE_INDEX_1
+# define index_arch_Prefer_No_AVX512   FEATURE_INDEX_1
+# define index_arch_XSAVEC_Usable      FEATURE_INDEX_1
 
 #endif /* !__ASSEMBLER__ */
 
index 5043b325631f9ec73eeaaa3aff13547639d6a267..95282a3ac7a4ed3478bfc0e9888425b2aa85b163 100644 (file)
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#define INIT_VEC_PTRS_LOOP(vec, val, len)                      \
-  do                                                           \
-    {                                                          \
-      for (i = 0; i < len; i++)                                        \
-        {                                                      \
-          vec[i] = &val[i];                                    \
-        }                                                      \
-    }                                                          \
+#define INIT_VEC_PTRS_LOOP(vec, val, len)                              \
+  do                                                                   \
+    {                                                                  \
+      union { VEC_INT_TYPE v; __typeof__ ((val)[0]) *a[(len)]; } u;    \
+      for (i = 0; i < len; i++)                                                \
+       u.a[i] = &(val)[i];                                             \
+      (vec) = u.v;                                                     \
+    }                                                                  \
   while (0)
 
 /* Wrapper for vector sincos/sincosf compatible with x86_64 and x32 variants
@@ -40,8 +40,8 @@ void scalar_func (FLOAT x, FLOAT * r, FLOAT * r1)             \
   VEC_TYPE mx;                                                 \
   VEC_INT_TYPE mr, mr1;                                                \
   INIT_VEC_LOOP (mx, x, VEC_LEN);                              \
-  INIT_VEC_PTRS_LOOP (((FLOAT **) &mr), r_loc, VEC_LEN);       \
-  INIT_VEC_PTRS_LOOP (((FLOAT **) &mr1), r1_loc, VEC_LEN);     \
+  INIT_VEC_PTRS_LOOP (mr, r_loc, VEC_LEN);                     \
+  INIT_VEC_PTRS_LOOP (mr1, r1_loc, VEC_LEN);                   \
   vector_func (mx, mr, mr1);                                   \
   TEST_VEC_LOOP (r_loc, VEC_LEN);                              \
   TEST_VEC_LOOP (r1_loc, VEC_LEN);                             \
@@ -63,8 +63,8 @@ void scalar_func (FLOAT x, FLOAT * r, FLOAT * r1)             \
   VEC_TYPE mx;                                                 \
   VEC_INT_TYPE mr, mr1;                                                \
   INIT_VEC_LOOP (mx, x, VEC_LEN);                              \
-  INIT_VEC_PTRS_LOOP (((FLOAT **) &mr), r_loc, VEC_LEN/2);     \
-  INIT_VEC_PTRS_LOOP (((FLOAT **) &mr1), r1_loc, VEC_LEN/2);   \
+  INIT_VEC_PTRS_LOOP (mr, r_loc, VEC_LEN/2);                   \
+  INIT_VEC_PTRS_LOOP (mr1, r1_loc, VEC_LEN/2);                 \
   vector_func (mx, mr, mr, mr1, mr1);                          \
   TEST_VEC_LOOP (r_loc, VEC_LEN/2);                            \
   TEST_VEC_LOOP (r1_loc, VEC_LEN/2);                           \
@@ -87,8 +87,8 @@ void scalar_func (FLOAT x, FLOAT * r, FLOAT * r1)             \
   VEC_TYPE mx;                                                 \
   VEC_INT_TYPE mr, mr1;                                                \
   INIT_VEC_LOOP (mx, x, VEC_LEN);                              \
-  INIT_VEC_PTRS_LOOP (((FLOAT **) &mr), r_loc, VEC_LEN/4);     \
-  INIT_VEC_PTRS_LOOP (((FLOAT **) &mr1), r1_loc, VEC_LEN/4);   \
+  INIT_VEC_PTRS_LOOP (mr, r_loc, VEC_LEN/4);                   \
+  INIT_VEC_PTRS_LOOP (mr1, r1_loc, VEC_LEN/4);                 \
   vector_func (mx, mr, mr, mr, mr, mr1, mr1, mr1, mr1);                \
   TEST_VEC_LOOP (r_loc, VEC_LEN/4);                            \
   TEST_VEC_LOOP (r1_loc, VEC_LEN/4);                           \
index 5f25893dc9ff12565f3f64a25e89050286787a79..132470d9cb83c2a56050d4916e6490e85df2e000 100644 (file)
@@ -27,7 +27,7 @@ ifeq ($(subdir),elf)
 CFLAGS-.os += $(if $(filter $(@F),$(patsubst %,%.os,$(all-rtld-routines))),\
                   -mno-mmx)
 
-sysdep-dl-routines += tlsdesc dl-tlsdesc
+sysdep-dl-routines += tlsdesc dl-tlsdesc tls_get_addr
 
 tests += ifuncmain8
 modules-names += ifuncmod8
@@ -52,9 +52,12 @@ $(objpfx)tst-quad2pie: $(objpfx)tst-quadmod2pie.o
 CFLAGS-tst-quad1pie.c = $(PIE-ccflag)
 CFLAGS-tst-quad2pie.c = $(PIE-ccflag)
 
-tests += tst-audit3 tst-audit4 tst-audit5 tst-audit6 tst-audit7 tst-audit10
-test-extras += tst-audit4-aux tst-audit10-aux
-extra-test-objs += tst-audit4-aux.o tst-audit10-aux.o
+tests += tst-audit3 tst-audit4 tst-audit5 tst-audit6 tst-audit7 \
+        tst-audit10 tst-sse tst-avx tst-avx512
+test-extras += tst-audit4-aux tst-audit10-aux \
+              tst-avx-aux tst-avx512-aux
+extra-test-objs += tst-audit4-aux.o tst-audit10-aux.o \
+                  tst-avx-aux.o tst-avx512-aux.o
 
 tests += tst-split-dynreloc
 LDFLAGS-tst-split-dynreloc = -Wl,-T,$(..)sysdeps/x86_64/tst-split-dynreloc.lds
@@ -65,7 +68,8 @@ modules-names += tst-auditmod3a tst-auditmod3b \
                tst-auditmod5a tst-auditmod5b \
                tst-auditmod6a tst-auditmod6b tst-auditmod6c \
                tst-auditmod7a tst-auditmod7b \
-               tst-auditmod10a tst-auditmod10b
+               tst-auditmod10a tst-auditmod10b \
+               tst-ssemod tst-avxmod tst-avx512mod
 
 $(objpfx)tst-audit3: $(objpfx)tst-auditmod3a.so
 $(objpfx)tst-audit3.out: $(objpfx)tst-auditmod3b.so
@@ -92,6 +96,10 @@ $(objpfx)tst-audit10: $(objpfx)tst-audit10-aux.o $(objpfx)tst-auditmod10a.so
 $(objpfx)tst-audit10.out: $(objpfx)tst-auditmod10b.so
 tst-audit10-ENV = LD_AUDIT=$(objpfx)tst-auditmod10b.so
 
+$(objpfx)tst-sse: $(objpfx)tst-ssemod.so
+$(objpfx)tst-avx: $(objpfx)tst-avx-aux.o $(objpfx)tst-avxmod.so
+$(objpfx)tst-avx512: $(objpfx)tst-avx512-aux.o $(objpfx)tst-avx512mod.so
+
 AVX-CFLAGS=-mavx -mno-vzeroupper
 CFLAGS-tst-audit4-aux.c += $(AVX-CFLAGS)
 CFLAGS-tst-auditmod4a.c += $(AVX-CFLAGS)
@@ -99,14 +107,18 @@ CFLAGS-tst-auditmod4b.c += $(AVX-CFLAGS)
 CFLAGS-tst-auditmod6b.c += $(AVX-CFLAGS)
 CFLAGS-tst-auditmod6c.c += $(AVX-CFLAGS)
 CFLAGS-tst-auditmod7b.c += $(AVX-CFLAGS)
+CFLAGS-tst-avx-aux.c += $(AVX-CFLAGS)
+CFLAGS-tst-avxmod.c += $(AVX-CFLAGS)
 ifeq (yes,$(config-cflags-avx512))
 AVX512-CFLAGS = -mavx512f
 CFLAGS-tst-audit10-aux.c += $(AVX512-CFLAGS)
 CFLAGS-tst-auditmod10a.c += $(AVX512-CFLAGS)
 CFLAGS-tst-auditmod10b.c += $(AVX512-CFLAGS)
+CFLAGS-tst-avx512-aux.c += $(AVX512-CFLAGS)
+CFLAGS-tst-avx512mod.c += $(AVX512-CFLAGS)
 endif
 endif
 
 ifeq ($(subdir),csu)
-gen-as-const-headers += tlsdesc.sym
+gen-as-const-headers += tlsdesc.sym rtld-offsets.sym
 endif
index daf4d8c0703eb801f6ce78fcbc56cd0596687ef6..be0b8616ea48e58155d57d693f996211597f8aed 100644 (file)
@@ -66,12 +66,9 @@ static inline int __attribute__ ((unused, always_inline))
 elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
 {
   Elf64_Addr *got;
-  extern void _dl_runtime_resolve_sse (ElfW(Word)) attribute_hidden;
-  extern void _dl_runtime_resolve_avx (ElfW(Word)) attribute_hidden;
-  extern void _dl_runtime_resolve_avx_slow (ElfW(Word)) attribute_hidden;
-  extern void _dl_runtime_resolve_avx_opt (ElfW(Word)) attribute_hidden;
-  extern void _dl_runtime_resolve_avx512 (ElfW(Word)) attribute_hidden;
-  extern void _dl_runtime_resolve_avx512_opt (ElfW(Word)) attribute_hidden;
+  extern void _dl_runtime_resolve_fxsave (ElfW(Word)) attribute_hidden;
+  extern void _dl_runtime_resolve_xsave (ElfW(Word)) attribute_hidden;
+  extern void _dl_runtime_resolve_xsavec (ElfW(Word)) attribute_hidden;
   extern void _dl_runtime_profile_sse (ElfW(Word)) attribute_hidden;
   extern void _dl_runtime_profile_avx (ElfW(Word)) attribute_hidden;
   extern void _dl_runtime_profile_avx512 (ElfW(Word)) attribute_hidden;
@@ -120,29 +117,14 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
          /* This function will get called to fix up the GOT entry
             indicated by the offset on the stack, and then jump to
             the resolved address.  */
-         if (HAS_ARCH_FEATURE (AVX512F_Usable))
-           {
-             if (HAS_ARCH_FEATURE (Use_dl_runtime_resolve_opt))
-               *(ElfW(Addr) *) (got + 2)
-                 = (ElfW(Addr)) &_dl_runtime_resolve_avx512_opt;
-             else
-               *(ElfW(Addr) *) (got + 2)
-                 = (ElfW(Addr)) &_dl_runtime_resolve_avx512;
-           }
-         else if (HAS_ARCH_FEATURE (AVX_Usable))
-           {
-             if (HAS_ARCH_FEATURE (Use_dl_runtime_resolve_opt))
-               *(ElfW(Addr) *) (got + 2)
-                 = (ElfW(Addr)) &_dl_runtime_resolve_avx_opt;
-             else if (HAS_ARCH_FEATURE (Use_dl_runtime_resolve_slow))
-               *(ElfW(Addr) *) (got + 2)
-                 = (ElfW(Addr)) &_dl_runtime_resolve_avx_slow;
-             else
-               *(ElfW(Addr) *) (got + 2)
-                 = (ElfW(Addr)) &_dl_runtime_resolve_avx;
-           }
+         if (GLRO(dl_x86_cpu_features).xsave_state_size != 0)
+           *(ElfW(Addr) *) (got + 2)
+             = (HAS_ARCH_FEATURE (XSAVEC_Usable)
+                ? (ElfW(Addr)) &_dl_runtime_resolve_xsavec
+                : (ElfW(Addr)) &_dl_runtime_resolve_xsave);
          else
-           *(ElfW(Addr) *) (got + 2) = (ElfW(Addr)) &_dl_runtime_resolve_sse;
+           *(ElfW(Addr) *) (got + 2)
+             = (ElfW(Addr)) &_dl_runtime_resolve_fxsave;
        }
     }
 
diff --git a/sysdeps/x86_64/dl-tls.c b/sysdeps/x86_64/dl-tls.c
new file mode 100644 (file)
index 0000000..3584805
--- /dev/null
@@ -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
+   <http://www.gnu.org/licenses/>.  */
+
+#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 <dl-tls.h>
+
+/* 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 <elf/dl-tls.c>
+# 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 <elf/dl-tls.c>
+
+#endif
index 4a59d2a924c14529b1eac7a125a1f329fcd9b8bf..c2fb56c0a1899be647ee4cb3a491c638b8aca203 100644 (file)
@@ -16,6 +16,9 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#ifndef _X86_64_DL_TLS_H
+#define _X86_64_DL_TLS_H
+
 #include <stdint.h>
 
 /* 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 */
index 33d7fcf7d079f717c240baa25da22f89d1d960dd..a645572e4434225fe3ad38db9bd3b704fea252d2 100644 (file)
 # 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)
 
 #define VEC_SIZE               64
 #define VMOVA                  vmovdqa64
-#if DL_RUNTIME_RESOLVE_REALIGN_STACK || VEC_SIZE <= DL_STACK_ALIGNMENT
-# define VMOV                  vmovdqa64
-#else
-# define VMOV                  vmovdqu64
-#endif
 #define VEC(i)                 zmm##i
-#define _dl_runtime_resolve    _dl_runtime_resolve_avx512
-#define _dl_runtime_resolve_opt        _dl_runtime_resolve_avx512_opt
 #define _dl_runtime_profile    _dl_runtime_profile_avx512
 #include "dl-trampoline.h"
-#undef _dl_runtime_resolve
-#undef _dl_runtime_resolve_opt
 #undef _dl_runtime_profile
 #undef VEC
-#undef VMOV
 #undef VMOVA
 #undef VEC_SIZE
 
 #define VEC_SIZE               32
 #define VMOVA                  vmovdqa
-#if DL_RUNTIME_RESOLVE_REALIGN_STACK || VEC_SIZE <= DL_STACK_ALIGNMENT
-# define VMOV                  vmovdqa
-#else
-# define VMOV                  vmovdqu
-#endif
 #define VEC(i)                 ymm##i
-#define _dl_runtime_resolve    _dl_runtime_resolve_avx
-#define _dl_runtime_resolve_opt        _dl_runtime_resolve_avx_opt
 #define _dl_runtime_profile    _dl_runtime_profile_avx
 #include "dl-trampoline.h"
-#undef _dl_runtime_resolve
-#undef _dl_runtime_resolve_opt
 #undef _dl_runtime_profile
 #undef VEC
-#undef VMOV
 #undef VMOVA
 #undef VEC_SIZE
 
 /* movaps/movups is 1-byte shorter.  */
 #define VEC_SIZE               16
 #define VMOVA                  movaps
-#if DL_RUNTIME_RESOLVE_REALIGN_STACK || VEC_SIZE <= DL_STACK_ALIGNMENT
-# define VMOV                  movaps
-#else
-# define VMOV                  movups
-#endif
 #define VEC(i)                 xmm##i
-#define _dl_runtime_resolve    _dl_runtime_resolve_sse
 #define _dl_runtime_profile    _dl_runtime_profile_sse
 #undef RESTORE_AVX
 #include "dl-trampoline.h"
-#undef _dl_runtime_resolve
 #undef _dl_runtime_profile
-#undef VMOV
+#undef VEC
 #undef VMOVA
+#undef VEC_SIZE
 
-/* Used by _dl_runtime_resolve_avx_opt/_dl_runtime_resolve_avx512_opt
-   to preserve the full vector registers with zero upper bits.  */
-#define VMOVA                  vmovdqa
-#if DL_RUNTIME_RESOLVE_REALIGN_STACK || VEC_SIZE <= DL_STACK_ALIGNMENT
-# define VMOV                  vmovdqa
-#else
-# define VMOV                  vmovdqu
-#endif
-#define _dl_runtime_resolve    _dl_runtime_resolve_sse_vex
+#define USE_FXSAVE
+#define STATE_SAVE_ALIGNMENT   16
+#define _dl_runtime_resolve    _dl_runtime_resolve_fxsave
+#include "dl-trampoline.h"
+#undef _dl_runtime_resolve
+#undef USE_FXSAVE
+#undef STATE_SAVE_ALIGNMENT
+
+#define USE_XSAVE
+#define STATE_SAVE_ALIGNMENT   64
+#define _dl_runtime_resolve    _dl_runtime_resolve_xsave
+#include "dl-trampoline.h"
+#undef _dl_runtime_resolve
+#undef USE_XSAVE
+#undef STATE_SAVE_ALIGNMENT
+
+#define USE_XSAVEC
+#define STATE_SAVE_ALIGNMENT   64
+#define _dl_runtime_resolve    _dl_runtime_resolve_xsavec
 #include "dl-trampoline.h"
+#undef _dl_runtime_resolve
+#undef USE_XSAVEC
+#undef STATE_SAVE_ALIGNMENT
index b27fa0697469869a2275e5c3d09e5db64622db90..9ddaafee17b3e70cde862a4dd20b9815b1a521d3 100644 (file)
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#undef REGISTER_SAVE_AREA_RAW
-#ifdef __ILP32__
-/* X32 saves RCX, RDX, RSI, RDI, R8 and R9 plus RAX as well as VEC0 to
-   VEC7.  */
-# define REGISTER_SAVE_AREA_RAW        (8 * 7 + VEC_SIZE * 8)
-#else
-/* X86-64 saves RCX, RDX, RSI, RDI, R8 and R9 plus RAX as well as
-   BND0, BND1, BND2, BND3 and VEC0 to VEC7. */
-# define REGISTER_SAVE_AREA_RAW        (8 * 7 + 16 * 4 + VEC_SIZE * 8)
-#endif
+       .text
+#ifdef _dl_runtime_resolve
 
-#undef REGISTER_SAVE_AREA
-#undef LOCAL_STORAGE_AREA
-#undef BASE
-#if DL_RUNTIME_RESOLVE_REALIGN_STACK
-# define REGISTER_SAVE_AREA    (REGISTER_SAVE_AREA_RAW + 8)
-/* Local stack area before jumping to function address: RBX.  */
-# define LOCAL_STORAGE_AREA    8
-# define BASE                  rbx
-# if (REGISTER_SAVE_AREA % VEC_SIZE) != 0
-#  error REGISTER_SAVE_AREA must be multples of VEC_SIZE
-# endif
-#else
-# define REGISTER_SAVE_AREA    REGISTER_SAVE_AREA_RAW
-/* Local stack area before jumping to function address:  All saved
-   registers.  */
-# define LOCAL_STORAGE_AREA    REGISTER_SAVE_AREA
-# define BASE                  rsp
-# if (REGISTER_SAVE_AREA % 16) != 8
-#  error REGISTER_SAVE_AREA must be odd multples of 8
+# undef REGISTER_SAVE_AREA
+# undef LOCAL_STORAGE_AREA
+# undef BASE
+
+# if (STATE_SAVE_ALIGNMENT % 16) != 0
+#  error STATE_SAVE_ALIGNMENT must be multples of 16
 # endif
-#endif
 
-       .text
-#ifdef _dl_runtime_resolve_opt
-/* Use the smallest vector registers to preserve the full YMM/ZMM
-   registers to avoid SSE transition penalty.  */
-
-# if VEC_SIZE == 32
-/* Check if the upper 128 bits in %ymm0 - %ymm7 registers are non-zero
-   and preserve %xmm0 - %xmm7 registers with the zero upper bits.  Since
-   there is no SSE transition penalty on AVX512 processors which don't
-   support XGETBV with ECX == 1, _dl_runtime_resolve_avx512_slow isn't
-   provided.   */
-       .globl _dl_runtime_resolve_avx_slow
-       .hidden _dl_runtime_resolve_avx_slow
-       .type _dl_runtime_resolve_avx_slow, @function
-       .align 16
-_dl_runtime_resolve_avx_slow:
-       cfi_startproc
-       cfi_adjust_cfa_offset(16) # Incorporate PLT
-       vorpd %ymm0, %ymm1, %ymm8
-       vorpd %ymm2, %ymm3, %ymm9
-       vorpd %ymm4, %ymm5, %ymm10
-       vorpd %ymm6, %ymm7, %ymm11
-       vorpd %ymm8, %ymm9, %ymm9
-       vorpd %ymm10, %ymm11, %ymm10
-       vpcmpeqd %xmm8, %xmm8, %xmm8
-       vorpd %ymm9, %ymm10, %ymm10
-       vptest %ymm10, %ymm8
-       # Preserve %ymm0 - %ymm7 registers if the upper 128 bits of any
-       # %ymm0 - %ymm7 registers aren't zero.
-       PRESERVE_BND_REGS_PREFIX
-       jnc _dl_runtime_resolve_avx
-       # Use vzeroupper to avoid SSE transition penalty.
-       vzeroupper
-       # Preserve %xmm0 - %xmm7 registers with the zero upper 128 bits
-       # when the upper 128 bits of %ymm0 - %ymm7 registers are zero.
-       PRESERVE_BND_REGS_PREFIX
-       jmp _dl_runtime_resolve_sse_vex
-       cfi_adjust_cfa_offset(-16) # Restore PLT adjustment
-       cfi_endproc
-       .size _dl_runtime_resolve_avx_slow, .-_dl_runtime_resolve_avx_slow
+# if (STATE_SAVE_OFFSET % STATE_SAVE_ALIGNMENT) != 0
+#  error STATE_SAVE_OFFSET must be multples of STATE_SAVE_ALIGNMENT
 # endif
 
-/* Use XGETBV with ECX == 1 to check which bits in vector registers are
-   non-zero and only preserve the non-zero lower bits with zero upper
-   bits.  */
-       .globl _dl_runtime_resolve_opt
-       .hidden _dl_runtime_resolve_opt
-       .type _dl_runtime_resolve_opt, @function
-       .align 16
-_dl_runtime_resolve_opt:
-       cfi_startproc
-       cfi_adjust_cfa_offset(16) # Incorporate PLT
-       pushq %rax
-       cfi_adjust_cfa_offset(8)
-       cfi_rel_offset(%rax, 0)
-       pushq %rcx
-       cfi_adjust_cfa_offset(8)
-       cfi_rel_offset(%rcx, 0)
-       pushq %rdx
-       cfi_adjust_cfa_offset(8)
-       cfi_rel_offset(%rdx, 0)
-       movl $1, %ecx
-       xgetbv
-       movl %eax, %r11d
-       popq %rdx
-       cfi_adjust_cfa_offset(-8)
-       cfi_restore (%rdx)
-       popq %rcx
-       cfi_adjust_cfa_offset(-8)
-       cfi_restore (%rcx)
-       popq %rax
-       cfi_adjust_cfa_offset(-8)
-       cfi_restore (%rax)
-# if VEC_SIZE == 32
-       # For YMM registers, check if YMM state is in use.
-       andl $bit_YMM_state, %r11d
-       # Preserve %xmm0 - %xmm7 registers with the zero upper 128 bits if
-       # YMM state isn't in use.
-       PRESERVE_BND_REGS_PREFIX
-       jz _dl_runtime_resolve_sse_vex
-# elif VEC_SIZE == 64
-       # For ZMM registers, check if YMM state and ZMM state are in
-       # use.
-       andl $(bit_YMM_state | bit_ZMM0_15_state), %r11d
-       cmpl $bit_YMM_state, %r11d
-       # Preserve %xmm0 - %xmm7 registers with the zero upper 384 bits if
-       # neither YMM state nor ZMM state are in use.
-       PRESERVE_BND_REGS_PREFIX
-       jl _dl_runtime_resolve_sse_vex
-       # Preserve %ymm0 - %ymm7 registers with the zero upper 256 bits if
-       # ZMM state isn't in use.
-       PRESERVE_BND_REGS_PREFIX
-       je _dl_runtime_resolve_avx
+# if DL_RUNTIME_RESOLVE_REALIGN_STACK
+/* Local stack area before jumping to function address: RBX.  */
+#  define LOCAL_STORAGE_AREA   8
+#  define BASE                 rbx
+#  ifdef USE_FXSAVE
+/* Use fxsave to save XMM registers.  */
+#   define REGISTER_SAVE_AREA  (512 + STATE_SAVE_OFFSET)
+#   if (REGISTER_SAVE_AREA % 16) != 0
+#    error REGISTER_SAVE_AREA must be multples of 16
+#   endif
+#  endif
 # else
-#  error Unsupported VEC_SIZE!
+#  ifndef USE_FXSAVE
+#   error USE_FXSAVE must be defined
+#  endif
+/* Use fxsave to save XMM registers.  */
+#  define REGISTER_SAVE_AREA   (512 + STATE_SAVE_OFFSET + 8)
+/* Local stack area before jumping to function address:  All saved
+   registers.  */
+#  define LOCAL_STORAGE_AREA   REGISTER_SAVE_AREA
+#  define BASE                 rsp
+#  if (REGISTER_SAVE_AREA % 16) != 8
+#   error REGISTER_SAVE_AREA must be odd multples of 8
+#  endif
 # endif
-       cfi_adjust_cfa_offset(-16) # Restore PLT adjustment
-       cfi_endproc
-       .size _dl_runtime_resolve_opt, .-_dl_runtime_resolve_opt
-#endif
+
        .globl _dl_runtime_resolve
        .hidden _dl_runtime_resolve
        .type _dl_runtime_resolve, @function
@@ -156,21 +64,30 @@ _dl_runtime_resolve_opt:
        cfi_startproc
 _dl_runtime_resolve:
        cfi_adjust_cfa_offset(16) # Incorporate PLT
-#if DL_RUNTIME_RESOLVE_REALIGN_STACK
-# if LOCAL_STORAGE_AREA != 8
-#  error LOCAL_STORAGE_AREA must be 8
-# endif
+# if DL_RUNTIME_RESOLVE_REALIGN_STACK
+#  if LOCAL_STORAGE_AREA != 8
+#   error LOCAL_STORAGE_AREA must be 8
+#  endif
        pushq %rbx                      # push subtracts stack by 8.
        cfi_adjust_cfa_offset(8)
        cfi_rel_offset(%rbx, 0)
        mov %RSP_LP, %RBX_LP
        cfi_def_cfa_register(%rbx)
-       and $-VEC_SIZE, %RSP_LP
-#endif
+       and $-STATE_SAVE_ALIGNMENT, %RSP_LP
+# endif
+# ifdef REGISTER_SAVE_AREA
        sub $REGISTER_SAVE_AREA, %RSP_LP
-#if !DL_RUNTIME_RESOLVE_REALIGN_STACK
+#  if !DL_RUNTIME_RESOLVE_REALIGN_STACK
        cfi_adjust_cfa_offset(REGISTER_SAVE_AREA)
-#endif
+#  endif
+# else
+       # Allocate stack space of the required size to save the state.
+#  if IS_IN (rtld)
+       sub _rtld_local_ro+RTLD_GLOBAL_RO_DL_X86_CPU_FEATURES_OFFSET+XSAVE_STATE_SIZE_OFFSET(%rip), %RSP_LP
+#  else
+       sub _dl_x86_cpu_features+XSAVE_STATE_SIZE_OFFSET(%rip), %RSP_LP
+#  endif
+# endif
        # Preserve registers otherwise clobbered.
        movq %rax, REGISTER_SAVE_RAX(%rsp)
        movq %rcx, REGISTER_SAVE_RCX(%rsp)
@@ -179,59 +96,42 @@ _dl_runtime_resolve:
        movq %rdi, REGISTER_SAVE_RDI(%rsp)
        movq %r8, REGISTER_SAVE_R8(%rsp)
        movq %r9, REGISTER_SAVE_R9(%rsp)
-       VMOV %VEC(0), (REGISTER_SAVE_VEC_OFF)(%rsp)
-       VMOV %VEC(1), (REGISTER_SAVE_VEC_OFF + VEC_SIZE)(%rsp)
-       VMOV %VEC(2), (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 2)(%rsp)
-       VMOV %VEC(3), (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 3)(%rsp)
-       VMOV %VEC(4), (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 4)(%rsp)
-       VMOV %VEC(5), (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 5)(%rsp)
-       VMOV %VEC(6), (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 6)(%rsp)
-       VMOV %VEC(7), (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 7)(%rsp)
-#ifndef __ILP32__
-       # We also have to preserve bound registers.  These are nops if
-       # Intel MPX isn't available or disabled.
-# ifdef HAVE_MPX_SUPPORT
-       bndmov %bnd0, REGISTER_SAVE_BND0(%rsp)
-       bndmov %bnd1, REGISTER_SAVE_BND1(%rsp)
-       bndmov %bnd2, REGISTER_SAVE_BND2(%rsp)
-       bndmov %bnd3, REGISTER_SAVE_BND3(%rsp)
+# ifdef USE_FXSAVE
+       fxsave STATE_SAVE_OFFSET(%rsp)
 # else
-#  if REGISTER_SAVE_BND0 == 0
-       .byte 0x66,0x0f,0x1b,0x04,0x24
+       movl $STATE_SAVE_MASK, %eax
+       xorl %edx, %edx
+       # Clear the XSAVE Header.
+#  ifdef USE_XSAVE
+       movq %rdx, (STATE_SAVE_OFFSET + 512)(%rsp)
+       movq %rdx, (STATE_SAVE_OFFSET + 512 + 8)(%rsp)
+#  endif
+       movq %rdx, (STATE_SAVE_OFFSET + 512 + 8 * 2)(%rsp)
+       movq %rdx, (STATE_SAVE_OFFSET + 512 + 8 * 3)(%rsp)
+       movq %rdx, (STATE_SAVE_OFFSET + 512 + 8 * 4)(%rsp)
+       movq %rdx, (STATE_SAVE_OFFSET + 512 + 8 * 5)(%rsp)
+       movq %rdx, (STATE_SAVE_OFFSET + 512 + 8 * 6)(%rsp)
+       movq %rdx, (STATE_SAVE_OFFSET + 512 + 8 * 7)(%rsp)
+#  ifdef USE_XSAVE
+       xsave STATE_SAVE_OFFSET(%rsp)
 #  else
-       .byte 0x66,0x0f,0x1b,0x44,0x24,REGISTER_SAVE_BND0
+       xsavec STATE_SAVE_OFFSET(%rsp)
 #  endif
-       .byte 0x66,0x0f,0x1b,0x4c,0x24,REGISTER_SAVE_BND1
-       .byte 0x66,0x0f,0x1b,0x54,0x24,REGISTER_SAVE_BND2
-       .byte 0x66,0x0f,0x1b,0x5c,0x24,REGISTER_SAVE_BND3
 # endif
-#endif
        # Copy args pushed by PLT in register.
        # %rdi: link_map, %rsi: reloc_index
        mov (LOCAL_STORAGE_AREA + 8)(%BASE), %RSI_LP
        mov LOCAL_STORAGE_AREA(%BASE), %RDI_LP
        call _dl_fixup          # Call resolver.
        mov %RAX_LP, %R11_LP    # Save return value
-#ifndef __ILP32__
-       # Restore bound registers.  These are nops if Intel MPX isn't
-       # avaiable or disabled.
-# ifdef HAVE_MPX_SUPPORT
-       bndmov REGISTER_SAVE_BND3(%rsp), %bnd3
-       bndmov REGISTER_SAVE_BND2(%rsp), %bnd2
-       bndmov REGISTER_SAVE_BND1(%rsp), %bnd1
-       bndmov REGISTER_SAVE_BND0(%rsp), %bnd0
+       # Get register content back.
+# ifdef USE_FXSAVE
+       fxrstor STATE_SAVE_OFFSET(%rsp)
 # else
-       .byte 0x66,0x0f,0x1a,0x5c,0x24,REGISTER_SAVE_BND3
-       .byte 0x66,0x0f,0x1a,0x54,0x24,REGISTER_SAVE_BND2
-       .byte 0x66,0x0f,0x1a,0x4c,0x24,REGISTER_SAVE_BND1
-#  if REGISTER_SAVE_BND0 == 0
-       .byte 0x66,0x0f,0x1a,0x04,0x24
-#  else
-       .byte 0x66,0x0f,0x1a,0x44,0x24,REGISTER_SAVE_BND0
-#  endif
+       movl $STATE_SAVE_MASK, %eax
+       xorl %edx, %edx
+       xrstor STATE_SAVE_OFFSET(%rsp)
 # endif
-#endif
-       # Get register content back.
        movq REGISTER_SAVE_R9(%rsp), %r9
        movq REGISTER_SAVE_R8(%rsp), %r8
        movq REGISTER_SAVE_RDI(%rsp), %rdi
@@ -239,20 +139,12 @@ _dl_runtime_resolve:
        movq REGISTER_SAVE_RDX(%rsp), %rdx
        movq REGISTER_SAVE_RCX(%rsp), %rcx
        movq REGISTER_SAVE_RAX(%rsp), %rax
-       VMOV (REGISTER_SAVE_VEC_OFF)(%rsp), %VEC(0)
-       VMOV (REGISTER_SAVE_VEC_OFF + VEC_SIZE)(%rsp), %VEC(1)
-       VMOV (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 2)(%rsp), %VEC(2)
-       VMOV (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 3)(%rsp), %VEC(3)
-       VMOV (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 4)(%rsp), %VEC(4)
-       VMOV (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 5)(%rsp), %VEC(5)
-       VMOV (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 6)(%rsp), %VEC(6)
-       VMOV (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 7)(%rsp), %VEC(7)
-#if DL_RUNTIME_RESOLVE_REALIGN_STACK
+# if DL_RUNTIME_RESOLVE_REALIGN_STACK
        mov %RBX_LP, %RSP_LP
        cfi_def_cfa_register(%rsp)
        movq (%rsp), %rbx
        cfi_restore(%rbx)
-#endif
+# endif
        # Adjust stack(PLT did 2 pushes)
        add $(LOCAL_STORAGE_AREA + 16), %RSP_LP
        cfi_adjust_cfa_offset(-(LOCAL_STORAGE_AREA + 16))
@@ -261,11 +153,9 @@ _dl_runtime_resolve:
        jmp *%r11               # Jump to function address.
        cfi_endproc
        .size _dl_runtime_resolve, .-_dl_runtime_resolve
+#endif
 
 
-/* To preserve %xmm0 - %xmm7 registers, dl-trampoline.h is included
-   twice, for _dl_runtime_resolve_sse and _dl_runtime_resolve_sse_vex.
-   But we don't need another _dl_runtime_profile for XMM registers.  */
 #if !defined PROF && defined _dl_runtime_profile
 # if (LR_VECTOR_OFFSET % VEC_SIZE) != 0
 #  error LR_VECTOR_OFFSET must be multples of VEC_SIZE
index 014a9f455430a3ba7fadb5422af189a95021e68e..a1840cff31cfbfbcc52d9ecb0d2a06baf445c25d 100644 (file)
@@ -8,7 +8,7 @@ libc.so: free + RELA R_X86_64_GLOB_DAT
 libc.so: malloc + RELA R_X86_64_GLOB_DAT
 libc.so: memalign + RELA R_X86_64_GLOB_DAT
 libc.so: realloc + RELA R_X86_64_GLOB_DAT
-libm.so: matherr
+libm.so: matherr + RELA R_X86_64_GLOB_DAT
 # The main malloc is interposed into the dynamic linker, for
 # allocations after the initial link (when dlopen is used).
 ld.so: malloc + RELA R_X86_64_GLOB_DAT
index f8a9260e6ea892f2084bef8d9983759725ba53a4..f9122915769067bc32f96f9db16a98385bd5c84a 100644 (file)
@@ -19,7 +19,7 @@
 #include <sysdep.h>
 #include "asm-syntax.h"
 
-#ifndef PIC
+#ifndef SHARED
        /* For libc.so this is defined in memcpy.S.
           For libc.a, this is a separate source to avoid
           mempcpy bringing in __chk_fail and all routines
index 1f83ee3e8477f57142c445275e653ae8544d9b65..af2770397ce69509205a904f6d433070b000e976 100644 (file)
@@ -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
index 54923420f114080d9ad0ca5ba1d09e3f00b722ad..8737fb9755d7fe12dfa31c9e8d5bf8ed1b06fd1d 100644 (file)
@@ -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
index 2021bfc30c65831fe0a1fa1b6f9ad7d353c78121..8c534e83e01198e6cbd4b69aa35c90a4d3f04c84 100644 (file)
@@ -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
index 8a252adcae5088d88e1c50dcb3e7c322cd5ff40d..7870dd0247e95455b11b3ba1e32343ea970f518e 100644 (file)
@@ -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
index 79c840d075aaf4f6476f2d4c3a1384da38c61021..b8b2b28094a6fac69125de060fc33f71826e5bc1 100644 (file)
@@ -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
index 6927962e81a6683696a50fcfa3ba09351e9cd84e..072b22c49f660f15dd43c72b70f2fc92897850b6 100644 (file)
@@ -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
index c958b2f49fb5e5c04e5a0a790ee7a7912d8787ba..9d33118cf832b7c6c411e66bcd4d9d43d2d51893 100644 (file)
@@ -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
index 79eaa37bb6291981ad9a648945f1735d427b2416..7e08311cdf48f88f5f2f1658e7c20f501ef210b9 100644 (file)
@@ -38,6 +38,8 @@ ENTRY(__memset_chk)
        jnz     L(AVX512F)
        lea     __memset_chk_avx2_unaligned(%rip), %RAX_LP
 L(AVX512F):
+       HAS_ARCH_FEATURE (Prefer_No_AVX512)
+       jnz     2f
        HAS_ARCH_FEATURE (AVX512F_Usable)
        jz      2f
        lea     __memset_chk_avx512_no_vzeroupper(%rip), %RAX_LP
diff --git a/sysdeps/x86_64/rtld-offsets.sym b/sysdeps/x86_64/rtld-offsets.sym
new file mode 100644 (file)
index 0000000..fd41b51
--- /dev/null
@@ -0,0 +1,6 @@
+#define SHARED
+#include <ldsodefs.h>
+
+--
+
+GL_TLS_GENERATION_OFFSET        offsetof (struct rtld_global, _dl_tls_generation)
diff --git a/sysdeps/x86_64/tls_get_addr.S b/sysdeps/x86_64/tls_get_addr.S
new file mode 100644 (file)
index 0000000..9d38fb3
--- /dev/null
@@ -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
+   <http://www.gnu.org/licenses/>.  */
+
+#ifdef SHARED
+
+# include <sysdep.h>
+# 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 */
index 33854975d04184b227a384a547e3dd75b53bf993..fc897ab4b522b1a9b611b0aff94f0823b76f9770 100644 (file)
@@ -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 (file)
index 0000000..e3807de
--- /dev/null
@@ -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
+   <http://www.gnu.org/licenses/>.  */
+
+#include <immintrin.h>
+#include <stdlib.h>
+#include <string.h>
+
+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 (file)
index 0000000..ec2e3a7
--- /dev/null
@@ -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
+   <http://www.gnu.org/licenses/>.  */
+
+#include <cpuid.h>
+
+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 (file)
index 0000000..6cebc52
--- /dev/null
@@ -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
+   <http://www.gnu.org/licenses/>.  */
+
+#include <immintrin.h>
+#include <stdlib.h>
+#include <string.h>
+
+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 (file)
index 0000000..a8e42ef
--- /dev/null
@@ -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
+   <http://www.gnu.org/licenses/>.  */
+
+#include <cpuid.h>
+
+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 (file)
index 0000000..4cfb3a2
--- /dev/null
@@ -0,0 +1,48 @@
+/* Test case for x86-64 preserved AVX512 registers in dynamic linker.  */
+
+#ifdef __AVX512F__
+#include <stdlib.h>
+#include <string.h>
+#include <immintrin.h>
+
+__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 (file)
index 0000000..6e5b154
--- /dev/null
@@ -0,0 +1,48 @@
+/* Test case for x86-64 preserved AVX registers in dynamic linker.  */
+
+#ifdef __AVX__
+#include <stdlib.h>
+#include <string.h>
+#include <immintrin.h>
+
+__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 (file)
index 0000000..dd1537c
--- /dev/null
@@ -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
+   <http://www.gnu.org/licenses/>.  */
+
+#include <immintrin.h>
+#include <stdlib.h>
+#include <string.h>
+
+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 (file)
index 0000000..907a64c
--- /dev/null
@@ -0,0 +1,46 @@
+/* Test case for x86-64 preserved SSE registers in dynamic linker.  */
+
+#include <stdlib.h>
+#include <string.h>
+#include <immintrin.h>
+
+__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);
+}