GIT update of git://sourceware.org/git/glibc.git/release/2.25/master from glibc-2.25
Gbp-Pq: Name git-updates.diff
+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"
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
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
$(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)
$(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
$(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
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
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
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
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
/* 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
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__
--- /dev/null
+/* 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>
--- /dev/null
+/* 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>
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@
INSTALL_INFO
PERL
BASH_SHELL
+CXX_BITS_STD_ABS_H
CXX_CMATH_HEADER
CXX_CSTDLIB_HEADER
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
+
# 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
# 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.
$(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
# define _TUNABLE_TYPES_H_
#include <stddef.h>
-typedef void (*tunable_callback_t) (void *);
-
typedef enum
{
TUNABLE_TYPE_INT_32,
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
if (cur->strval == NULL)
return;
+ /* Caller does not need the value, just call the callback with our tunable
+ value. */
if (valp == NULL)
goto cb;
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
/* 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,
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. */
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
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;
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);
}
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. */
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);
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 ();
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. */
break;
}
if (memcmp (envline, "AUDIT", 5) == 0)
- process_dl_audit (&envline[6]);
+ audit_list_string = &envline[6];
break;
case 7:
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;
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;
return 1;
}
+ if (getenv ("LD_HWCAP_MASK") != NULL)
+ {
+ printf ("LD_HWCAP_MASK still set\n");
+ return 1;
+ }
+
return 0;
}
#endif
return 1;
}
+ if (getenv ("LD_HWCAP_MASK") == NULL)
+ {
+ printf ("LD_HWCAP_MASK lost\n");
+ return 1;
+ }
+
return 0;
}
#endif
}
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];
/* 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++)
/* 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];
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))
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)
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)
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
--- /dev/null
+/* 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 (¤t_tv, NULL) == 0)
+ __libc_fatal ("Fatal error: gettimeofday system call failed\n");
+ result.current.tv_sec = current_tv.tv_sec;
+ result.current.tv_nsec = current_tv.tv_usec * 1000;
+ }
+ assert (result.current.tv_sec >= 0);
+ return result;
+}
+
+/* A special deadline value for which __deadline_is_infinite is
+ true. */
+static inline struct deadline
+infinite_deadline (void)
+{
+ return (struct deadline) { { -1, -1 } };
+}
+
+struct deadline internal_function
+__deadline_from_timeval (struct deadline_current_time current,
+ struct timeval tv)
+{
+ assert (__is_timeval_valid_timeout (tv));
+
+ /* Compute second-based deadline. Perform the addition in
+ uintmax_t, which is unsigned, to simply overflow detection. */
+ uintmax_t sec = current.current.tv_sec;
+ sec += tv.tv_sec;
+ if (sec < (uintmax_t) tv.tv_sec)
+ return infinite_deadline ();
+
+ /* Compute nanosecond deadline. */
+ int nsec = current.current.tv_nsec + tv.tv_usec * 1000;
+ if (nsec >= 1000 * 1000 * 1000)
+ {
+ /* Carry nanosecond overflow to seconds. */
+ nsec -= 1000 * 1000 * 1000;
+ if (sec + 1 < sec)
+ return infinite_deadline ();
+ ++sec;
+ }
+ /* This uses a GCC extension, otherwise these casts for detecting
+ overflow would not be defined. */
+ if ((time_t) sec < 0 || sec != (uintmax_t) (time_t) sec)
+ return infinite_deadline ();
+
+ return (struct deadline) { { sec, nsec } };
+}
+
+int internal_function
+__deadline_to_ms (struct deadline_current_time current,
+ struct deadline deadline)
+{
+ if (__deadline_is_infinite (deadline))
+ return INT_MAX;
+
+ if (current.current.tv_sec > deadline.absolute.tv_sec
+ || (current.current.tv_sec == deadline.absolute.tv_sec
+ && current.current.tv_nsec >= deadline.absolute.tv_nsec))
+ return 0;
+ time_t sec = deadline.absolute.tv_sec - current.current.tv_sec;
+ if (sec >= INT_MAX)
+ /* This value will overflow below. */
+ return INT_MAX;
+ int nsec = deadline.absolute.tv_nsec - current.current.tv_nsec;
+ if (nsec < 0)
+ {
+ /* Borrow from the seconds field. */
+ assert (sec > 0);
+ --sec;
+ nsec += 1000 * 1000 * 1000;
+ }
+
+ /* Prepare for rounding up to milliseconds. */
+ nsec += 999999;
+ if (nsec > 1000 * 1000 * 1000)
+ {
+ assert (sec < INT_MAX);
+ ++sec;
+ nsec -= 1000 * 1000 * 1000;
+ }
+
+ unsigned int msec = nsec / (1000 * 1000);
+ if (sec > INT_MAX / 1000)
+ return INT_MAX;
+ msec += sec * 1000;
+ if (msec > INT_MAX)
+ return INT_MAX;
+ return msec;
+}
#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 */
--- /dev/null
+/* 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>
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
+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
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>"
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>
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>
#
<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>
#
<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
<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
<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
<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
#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 ();
# 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); \
}
case M_ARENA_MAX:
if (value > 0)
- do_set_arena_test (value);
+ do_set_arena_max (value);
break;
}
__libc_lock_unlock (av->mutex);
#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);
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 \
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 \
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
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
$(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:
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
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)
__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
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
{
/* 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)
{
{
/* 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)
{
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.
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))
{
{
/* 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
}
}
- 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;
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)
&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;
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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>
#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)
{
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)
{
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)
{
--- /dev/null
+/* 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"
--- /dev/null
+/* 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>
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 \
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
$(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
$(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 ,\
--- /dev/null
+/* 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))
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. */
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
}
#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;
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
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)
{
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;
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;
}
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;
/* 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))
{
assert (next != NULL);
}
-#ifdef _LIBC
if (__glibc_unlikely (!alloca_onealt))
-#endif
free (onealt);
if (pglob->gl_pathc != firstc)
/* 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)
{
}
filename = pattern;
-#ifdef _AMIGA
- dirname = (char *) "";
-#else
dirname = (char *) ".";
-#endif
dirlen = 0;
}
}
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)
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] == '\\')
}
}
-#ifndef VMS
if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && dirname[0] == '~')
{
if (dirname[1] == '\0' || dirname[1] == '/'
/* 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
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')
{
{
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
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;
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
{
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
*p = '\0';
}
else
- *((char *) mempcpy (newp, dirname + 1, end_name - dirname))
+ *((char *) mempcpy (newp, dirname + 1, end_name - dirname - 1))
= '\0';
user_name = newp;
}
/* 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
{
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);
}
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
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;
}
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. */
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;
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;
}
/* Not found. */
- return GLOB_NOMATCH;
+ retval = GLOB_NOMATCH;
+ goto out;
}
meta = __glob_pattern_type (dirname, !(flags & GLOB_NOESCAPE));
if (status != 0)
{
if ((flags & GLOB_NOCHECK) == 0 || status != GLOB_NOMATCH)
- return status;
+ {
+ retval = status;
+ goto out;
+ }
goto no_matches;
}
{
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)
globfree (&dirs);
globfree (pglob);
pglob->gl_pathc = 0;
- return status;
+ retval = status;
+ goto out;
}
/* Stick the directory on the front of each name. */
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)
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;
else
{
globfree (&dirs);
- return GLOB_NOMATCH;
+ retval = GLOB_NOMATCH;
+ goto out;
}
}
flags = orig_flags;
goto no_matches;
}
- return status;
+ retval = status;
+ goto out;
}
if (dirlen > 0)
{
globfree (pglob);
pglob->gl_pathc = 0;
- return GLOB_NOSPACE;
+ retval = GLOB_NOSPACE;
+ goto out;
}
}
}
{
globfree (pglob);
pglob->gl_pathc = 0;
- return GLOB_NOSPACE;
+ retval = GLOB_NOSPACE;
+ goto out;
}
strcpy (&new[len - 2], "/");
pglob->gl_pathv[i] = new;
#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;
{
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
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)
{
char *endp = mempcpy (new, dirname, dirlen);
- *endp++ = DIRSEP_CHAR;
+ *endp++ = dirsep_char;
mempcpy (endp, array[i], eltlen);
}
free (array[i]);
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). */
{
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)))
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;
}
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;
}
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)
}
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))
{
{
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))
goto memory_error;
++cur;
++nfound;
+ if (SIZE_MAX - pglob->gl_offs <= nfound)
+ goto memory_error;
}
}
}
{
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:
and this is the block assigned to OLD here. */
if (names == NULL)
{
- assert (old == &init_names);
+ assert (old == init_names);
break;
}
cur = names->count;
and this is the block assigned to OLD here. */
if (names == NULL)
{
- assert (old == &init_names);
+ assert (old == init_names);
break;
}
cur = names->count;
}
libc_hidden_def (glob64)
-void
-globfree64 (glob64_t *pglob)
-{
-}
-libc_hidden_def (globfree64)
-
stub_warning (glob64)
--- /dev/null
+/* 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 */
--- /dev/null
+/* 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)
--- /dev/null
+/* 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
--- /dev/null
+/* 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)
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
fi
if test $result -eq 0; then
- chmod 777 $testdir/noread
- rm -fr $testdir $testout
echo "All OK." > $logfile
fi
--- /dev/null
+/* 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>
tst-res_hconf_reorder \
tst-res_use_inet6 \
tst-resolv-basic \
+ tst-resolv-edns \
tst-resolv-network \
tst-resolv-search \
$(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)
#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>
*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 */
return cp - buf;
}
-libresolv_hidden_def (__res_nopt)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <resolv/resolv-internal.h>
/* Options. Leave them on. */
/* #undef DEBUG */
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;
}
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;
}
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;
}
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 */
--- /dev/null
+/* 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>
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)
--- /dev/null
+#!/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
/* 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);
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;
}
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);
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)
{
|| (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;
}
adr[middle] = L('T');
}
}
+ if (outer == 0)
+ break;
}
/* Special test. */
}
/* 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)
{
|| (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;
}
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');
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');
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');
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 */
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;
}
{
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;
}
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;
}
/* 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;
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;
|| (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;
}
|| (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;
}
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;
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');
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;
}
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
}
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;
}
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)
$(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))
$(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)
#endif
#include <kernel-features.h>
+#include <inet/net-internal.h>
extern u_long _create_xid (void);
};
/*
- * 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
{
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)
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))
{
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);
}
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);
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 ();
}
/*
--- /dev/null
+/* 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>
--- /dev/null
+/* 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>
--- /dev/null
+/* 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>
--- /dev/null
+/* 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>
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 \
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 \
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 \
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 \
tests = \
README-testing \
tst-support-namespace \
+ tst-support_capture_subprocess \
+ tst-support_format_dns_packet \
tst-support_record_failure \
ifeq ($(run-built-tests),yes)
$(evaluate-test)
endif
+$(objpfx)tst-support_format_dns_packet: $(common-objpfx)resolv/libresolv.so
+
include ../Rules
--- /dev/null
+/* 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 */
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. */
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,
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
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.
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
#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
{
char qname[MAXDNAME];
uint16_t qclass;
uint16_t qtype;
+ struct resolv_edns_info edns;
};
/* Update *INFO from the specified DNS packet. */
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");
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);
+ }
}
.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
.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);
break;
}
- close (closure->client_socket);
+ xclose (closure->client_socket);
free (closure);
return NULL;
}
if (obj->termination_requested)
{
xpthread_mutex_unlock (&obj->lock);
- close (client_socket);
+ xclose (client_socket);
break;
}
xpthread_mutex_unlock (&obj->lock);
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");
}
}
+/* 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)
.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. */
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)
server_thread_udp);
if (config.servers[server_index].disable_tcp)
{
- close (server->socket_tcp);
+ xclose (server->socket_tcp);
server->socket_tcp = -1;
}
else
if (config.single_thread_udp)
start_server_thread_udp_single (obj);
+ if (config.disable_redirect)
+ return obj;
+
int timeout = 1;
/* Initialize libresolv. */
}
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)
{
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)
{
xconnect (sock,
(struct sockaddr *) &obj->servers[server_index].address,
sizeof (obj->servers[server_index].address));
- close (sock);
+ xclose (sock);
}
}
{
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);
}
}
__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
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
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
--- /dev/null
+/* 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);
+}
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. */
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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");
+ }
+}
--- /dev/null
+/* 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);
+}
#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;
req.ifr_flags |= IFF_UP | IFF_RUNNING;
TEST_VERIFY_EXIT (ioctl (fd, SIOCSIFFLAGS, &req) == 0);
}
- close (fd);
+ xclose (fd);
return !already_up;
}
}
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);
}
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);
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;
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;
}
}
}
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);
goto out;
}
/* Skip non-matching record types. */
- if (rtype != qtype || rclass != qclass)
+ if ((rtype != qtype && rtype != T_CNAME) || rclass != qclass)
continue;
switch (rtype)
{
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");
#include <support/format_nss.h>
#include <arpa/inet.h>
+#include <errno.h>
#include <stdio.h>
#include <support/support.h>
#include <support/xmemstream.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;
--- /dev/null
+/* 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);
+}
#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)
TEST_VERIFY_EXIT (fd >= 0);
free (template);
xwrite (fd, str, strlen (str));
- TEST_VERIFY_EXIT (close (fd) == 0);
+ xclose (fd);
return name;
}
--- /dev/null
+/* 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);
+}
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 '?':
#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);
}
--- /dev/null
+/* 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);
+}
#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
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);
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;
}
{
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");
}
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>
#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);
}
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
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;
}
--- /dev/null
+/* 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>
--- /dev/null
+/* 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>
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
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
}
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
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
+#include <string.h>
static int exit_status_with_failure = -1;
static bool test_verify;
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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 ();
+}
--- /dev/null
+/* 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 */
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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");
+}
--- /dev/null
+/* 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));
+}
--- /dev/null
+/* 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));
+}
--- /dev/null
+/* 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));
+}
--- /dev/null
+/* 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));
+}
--- /dev/null
+/* 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));
+}
--- /dev/null
+/* 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));
+}
--- /dev/null
+/* 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));
+}
void xbind (int, const struct sockaddr *, socklen_t);
void xlisten (int, int);
int xaccept (int, struct sockaddr *, socklen_t *);
+int xaccept4 (int, struct sockaddr *, socklen_t *, int);
void xsendto (int, const void *, size_t, int,
const struct sockaddr *, socklen_t);
size_t xrecvfrom (int, void *, size_t, int, struct sockaddr *, socklen_t *);
int 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 */
#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
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\
"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" \
#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)
--- /dev/null
+#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)
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"
: /* No outputs. */
: "r" (r25), "r" (r26)
: /* No point in clobbers. */ );
+
/* Avoid `volatile function does return' warnings. */
for (;;);
}
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);
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
.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 ())
#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. */
/* 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" \
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
/* 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
--- /dev/null
+/* 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>
/* 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;
Function: "acosh_upward":
double: 1
idouble: 1
-ildouble: 4
+ildouble: 5
ldouble: 3
Function: "asin":
float: 3
idouble: 3
ifloat: 3
-ildouble: 7
-ldouble: 7
+ildouble: 8
+ldouble: 8
Function: Imaginary part of "clog10_upward":
double: 1
float: 4
idouble: 3
ifloat: 4
-ildouble: 5
-ldouble: 5
+ildouble: 6
+ldouble: 6
Function: "hypot":
double: 1
float: 4
idouble: 3
ifloat: 4
-ildouble: 5
-ldouble: 5
+ildouble: 6
+ldouble: 6
Function: "log":
double: 1
# 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
add %ecx, %edx
sbb %eax, %eax
or %eax, %edx
+ sub $16, %edx
jbe L(return_null)
lea 16(%edi), %edi
# else
-#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
-#include <sysdeps/x86_64/multiarch/varshift.c>
+#if IS_IN (libc)
+# include <sysdeps/x86_64/multiarch/varshift.c>
+#endif
+++ /dev/null
-/* 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
--- /dev/null
+/* 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
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
{
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;
}
else
{
- assert (THREAD_GETMEM (THREAD_SELF, tid) == ppid);
-
/* Release acquired locks in the multi-threaded case. */
if (multiple_threads)
{
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"
{
/* 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;
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);
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
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
ifeq ($(subdir),posix)
sysdep_headers += bits/initspin.h
-sysdep_routines += sched_getcpu
+sysdep_routines += sched_getcpu oldglob
tests += tst-affinity tst-affinity-pid
#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)
--- /dev/null
+/* 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)
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
#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;
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. */
#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. */
/* 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.
/* Epilogue */
ldw -84(%sp), %r2
#ifdef PIC
- ldw -96(%sp), %r19
+ ldw -32(%sp), %r19
#endif
bv %r0(%r2)
ldwm -64(%sp), %r4
+++ /dev/null
-#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
--- /dev/null
+/* 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
libc.so: malloc
libc.so: memalign
libc.so: realloc
-libc.so: _exit
libc.so: __sigsetjmp
libc.so: _IO_funlockfile
libc.so: sigprocmask
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
#include <bits/pthreadtypes.h>
#include <bits/setjmp.h>
#include <bits/wordsize.h>
+#include <bits/types/struct_timespec.h>
/* Detach state. */
#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
# 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 */
};
-
/* 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 */
__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
+++ /dev/null
-/* 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
+++ /dev/null
-/* 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
+++ /dev/null
-/* 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
+++ /dev/null
-/* 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
+++ /dev/null
-/* 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
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. */
/* No further context available. Exit now. */
bl HIDDEN_JUMPTARGET(exit), %r2
- ldi -1, %r26
+ ldi 0, %r26
.Lerror:
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 \
/* 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 \
/* 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
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
#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
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
--- /dev/null
+/* glob64 is in globfree64.c */
_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);
--- /dev/null
+#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
/* 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)) */
+++ /dev/null
-/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
<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
__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
/* 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);
/* 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;
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;
--- /dev/null
+/* This file is here so sysdeps/gnu/glob64.c doesn't take precedence. */
+#include <sysdeps/wordsize-64/globfree64.c>
--- /dev/null
+#include <sysdeps/wordsize-64/globfree.c>
#undef glob64
#undef globfree64
weak_alias (glob, glob64)
-weak_alias (globfree, globfree64)
-libc_hidden_ver (globfree, globfree64)
--- /dev/null
+#define globfree64 __no_globfree64_decl
+#include <posix/globfree.c>
+#undef globfree64
+weak_alias (globfree, globfree64)
+libc_hidden_ver (globfree, globfree64)
--- /dev/null
+/* globfree64 is in globfree.c */
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)
#include <cpuid.h>
#include <cpu-features.h>
+#include <libc-internal.h>
static void
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;
+ }
+ }
+ }
+ }
}
}
case 0x57:
/* Knights Landing. Enable Silvermont optimizations. */
- cpu_features->feature[index_arch_Prefer_No_VZEROUPPER]
- |= bit_arch_Prefer_No_VZEROUPPER;
case 0x5c:
case 0x5f:
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)
#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)
} 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];
};
# 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
# 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
# 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__ */
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
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); \
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); \
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); \
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
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
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
$(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)
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
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;
/* 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;
}
}
--- /dev/null
+/* 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
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. */
extern void *__tls_get_addr (tls_index *ti);
+
+#endif /* _X86_64_DL_TLS_H */
# 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
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
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)
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
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))
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
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
#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
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
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
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
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
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
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
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
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
--- /dev/null
+#define SHARED
+#include <ldsodefs.h>
+
+--
+
+GL_TLS_GENERATION_OFFSET offsetof (struct rtld_global, _dl_tls_generation)
--- /dev/null
+/* 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 */
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)
--- /dev/null
+/* 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__ */
+}
--- /dev/null
+/* 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"
--- /dev/null
+/* 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__ */
+}
--- /dev/null
+/* 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"
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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"
--- /dev/null
+/* 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);
+}