diff --git a/ChangeLog b/ChangeLog index c44c926094..cd499c5fe3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,887 @@ +2018-01-12 Dmitry V. Levin + + [BZ #22679] + CVE-2018-1000001 + * sysdeps/unix/sysv/linux/getcwd.c (__getcwd): Fall back to + generic_getcwd if the path returned by getcwd syscall is not absolute. + * io/tst-getcwd-abspath.c: New test. + * io/Makefile (tests): Add tst-getcwd-abspath. + + (gaih_inet): Likewise. + +2017-12-30 Aurelien Jarno + + [BZ #22625] + * elf/dl-load.c (fillin_rpath): Check for empty tokens before dynamic + string token expansion. Check for NULL pointer or empty string possibly + returned by expand_dynamic_string_token. + (decompose_rpath): Check for empty path after dynamic string + token expansion. + +2017-12-18 Dmitry V. Levin + + [BZ #22627] + * elf/dl-load.c (_dl_init_paths): Remove _dl_dst_substitute preparatory + code and invocation. + +2017-12-14 Florian Weimer + + [BZ #22607] + CVE-2017-1000409 + * elf/dl-load.c (_dl_init_paths): Compute number of components in + the expanded path string. + +2017-12-14 Florian Weimer + + [BZ #22606] + CVE-2017-1000408 + * elf/dl-load.c (system_dirs): Update comment. + (nsystem_dirs_len): Use array_length. + (_dl_init_paths): Use nsystem_dirs_len to compute the array size. + +2017-11-02 Florian Weimer + + Add array_length and array_end macros. + * include/array_length.h: New file. + +2017-11-02 Florian Weimer + + [BZ #22332] + * posix/tst-glob-tilde.c (do_noescape): New variable. + (one_test): Process it. + (do_test): Set do_noescape. Add unescaping test case. + +2017-10-22 Paul Eggert + + [BZ #22332] + * posix/glob.c (__glob): Fix buffer overflow during GLOB_TILDE + unescaping. + +2017-10-21 Florian Weimer + + * posix/Makefile (tests): Add tst-glob-tilde. + (tests-special): Add tst-glob-tilde-mem.out + (tst-glob-tilde-ENV): Set MALLOC_TRACE. + (tst-glob-tilde-mem.out): Add mtrace check. + * posix/tst-glob-tilde.c: New file. + +2017-10-20 Paul Eggert + + [BZ #22320] + CVE-2017-15670 + * posix/glob.c (__glob): Fix one-byte overflow. + +2017-09-08 Adhemerval Zanella + + [BZ #1062] + CVE-2017-15671 + * posix/Makefile (routines): Add globfree, globfree64, and + glob_pattern_p. + * posix/flexmember.h: New file. + * posix/glob_internal.h: Likewise. + * posix/glob_pattern_p.c: Likewise. + * posix/globfree.c: Likewise. + * posix/globfree64.c: Likewise. + * sysdeps/gnu/globfree64.c: Likewise. + * sysdeps/unix/sysv/linux/alpha/globfree.c: Likewise. + * sysdeps/unix/sysv/linux/mips/mips64/n64/globfree64.c: Likewise. + * sysdeps/unix/sysv/linux/oldglob.c: Likewise. + * sysdeps/unix/sysv/linux/wordsize-64/globfree64.c: Likewise. + * sysdeps/unix/sysv/linux/x86_64/x32/globfree.c: Likewise. + * sysdeps/wordsize-64/globfree.c: Likewise. + * sysdeps/wordsize-64/globfree64.c: Likewise. + * posix/glob.c (HAVE_CONFIG_H): Use !_LIBC instead. + [NDEBUG): Remove comments. + (GLOB_ONLY_P, _AMIGA, VMS): Remove define. + (dirent_type): New type. Use uint_fast8_t not + uint8_t, as C99 does not require uint8_t. + (DT_UNKNOWN, DT_DIR, DT_LNK): New macros. + (struct readdir_result): Use dirent_type. Do not define skip_entry + unless it is needed; this saves a byte on platforms lacking d_ino. + (readdir_result_type, readdir_result_skip_entry): + New functions, replacing ... + (readdir_result_might_be_symlink, readdir_result_might_be_dir): + these functions, which were removed. This makes the callers + easier to read. All callers changed. + (D_INO_TO_RESULT): Now empty if there is no d_ino. + (size_add_wrapv, glob_use_alloca): New static functions. + (glob, glob_in_dir): Check for size_t overflow in several places, + and fix some size_t checks that were not quite right. + Remove old code using SHELL since Bash no longer + uses this. + (glob, prefix_array): Separate MS code better. + (glob_in_dir): Remove old Amiga and VMS code. + (globfree, __glob_pattern_type, __glob_pattern_p): Move to + separate files. + (glob_in_dir): Do not rely on undefined behavior in accessing + struct members beyond their bounds. Use a flexible array member + instead + (link_stat): Rename from link_exists2_p and return -1/0 instead of + 0/1. Caller changed. + (glob): Fix memory leaks. + * posix/glob64 (globfree64): Move to separate file. + * sysdeps/gnu/glob64.c (NO_GLOB_PATTERN_P): Remove define. + (globfree64): Remove hidden alias. + * sysdeps/unix/sysv/linux/Makefile (sysdeps_routines): Add + oldglob. + * sysdeps/unix/sysv/linux/alpha/glob.c (__new_globfree): Move to + separate file. + * sysdeps/unix/sysv/linux/i386/glob64.c (NO_GLOB_PATTERN_P): Remove + define. + Move compat code to separate file. + * sysdeps/wordsize-64/glob.c (globfree): Move definitions to + separate file. + +2017-08-20 H.J. Lu + + [BZ #18822] + * sysdeps/unix/sysv/linux/i386/glob64.c (__old_glob64): Add + libc_hidden_proto and libc_hidden_def. + +2017-10-22 H.J. Lu + + [BZ #21265] + * sysdeps/x86/cpu-features-offsets.sym (XSAVE_STATE_SIZE_OFFSET): + New. + * sysdeps/x86/cpu-features.c: Include . + (get_common_indeces): Set xsave_state_size and + bit_arch_XSAVEC_Usable if needed. + (init_cpu_features): Remove bit_arch_Use_dl_runtime_resolve_slow + and bit_arch_Use_dl_runtime_resolve_opt. + * sysdeps/x86/cpu-features.h (bit_arch_Use_dl_runtime_resolve_opt): + Removed. + (bit_arch_Use_dl_runtime_resolve_slow): Likewise. + (bit_arch_Prefer_No_AVX512): Updated. + (bit_arch_MathVec_Prefer_No_AVX512): Likewise. + (bit_arch_XSAVEC_Usable): New. + (STATE_SAVE_OFFSET): Likewise. + (STATE_SAVE_MASK): Likewise. + [__ASSEMBLER__]: Include . + (cpu_features): Add xsave_state_size. + (index_arch_Use_dl_runtime_resolve_opt): Removed. + (index_arch_Use_dl_runtime_resolve_slow): Likewise. + (index_arch_XSAVEC_Usable): New. + * sysdeps/x86_64/dl-machine.h (elf_machine_runtime_setup): + Replace _dl_runtime_resolve_sse, _dl_runtime_resolve_avx, + _dl_runtime_resolve_avx_slow, _dl_runtime_resolve_avx_opt, + _dl_runtime_resolve_avx512 and _dl_runtime_resolve_avx512_opt + with _dl_runtime_resolve_fxsave, _dl_runtime_resolve_xsave and + _dl_runtime_resolve_xsavec. + * sysdeps/x86_64/dl-trampoline.S (DL_RUNTIME_UNALIGNED_VEC_SIZE): + Removed. + (DL_RUNTIME_RESOLVE_REALIGN_STACK): Check STATE_SAVE_ALIGNMENT + instead of VEC_SIZE. + (REGISTER_SAVE_BND0): Removed. + (REGISTER_SAVE_BND1): Likewise. + (REGISTER_SAVE_BND3): Likewise. + (REGISTER_SAVE_RAX): Always defined to 0. + (VMOV): Removed. + (_dl_runtime_resolve_avx): Likewise. + (_dl_runtime_resolve_avx_slow): Likewise. + (_dl_runtime_resolve_avx_opt): Likewise. + (_dl_runtime_resolve_avx512): Likewise. + (_dl_runtime_resolve_avx512_opt): Likewise. + (_dl_runtime_resolve_sse): Likewise. + (_dl_runtime_resolve_sse_vex): Likewise. + (USE_FXSAVE): New. + (_dl_runtime_resolve_fxsave): Likewise. + (USE_XSAVE): Likewise. + (_dl_runtime_resolve_xsave): Likewise. + (USE_XSAVEC): Likewise. + (_dl_runtime_resolve_xsavec): Likewise. + * sysdeps/x86_64/dl-trampoline.h (_dl_runtime_resolve_avx512): + Removed. + (_dl_runtime_resolve_avx512_opt): Likewise. + (_dl_runtime_resolve_avx): Likewise. + (_dl_runtime_resolve_avx_opt): Likewise. + (_dl_runtime_resolve_sse): Likewise. + (_dl_runtime_resolve_sse_vex): Likewise. + (_dl_runtime_resolve_fxsave): New. + (_dl_runtime_resolve_xsave): Likewise. + (_dl_runtime_resolve_xsavec): Likewise. + +2017-10-19 H.J. Lu + + * sysdeps/x86_64/Makefile (tests): Add tst-sse, tst-avx and + tst-avx512. + (test-extras): Add tst-avx-aux and tst-avx512-aux. + (extra-test-objs): Add tst-avx-aux.o and tst-avx512-aux.o. + (modules-names): Add tst-ssemod, tst-avxmod and tst-avx512mod. + ($(objpfx)tst-sse): New rule. + ($(objpfx)tst-avx): Likewise. + ($(objpfx)tst-avx512): Likewise. + (CFLAGS-tst-avx-aux.c): New. + (CFLAGS-tst-avxmod.c): Likewise. + (CFLAGS-tst-avx512-aux.c): Likewise. + (CFLAGS-tst-avx512mod.c): Likewise. + * sysdeps/x86_64/tst-avx-aux.c: New file. + * sysdeps/x86_64/tst-avx.c: Likewise. + * sysdeps/x86_64/tst-avx512-aux.c: Likewise. + * sysdeps/x86_64/tst-avx512.c: Likewise. + * sysdeps/x86_64/tst-avx512mod.c: Likewise. + * sysdeps/x86_64/tst-avxmod.c: Likewise. + * sysdeps/x86_64/tst-sse.c: Likewise. + * sysdeps/x86_64/tst-ssemod.c: Likewise. + +2017-10-19 H.J. Lu + + * sysdeps/x86_64/dl-trampoline.h (_dl_runtime_resolve): Don't + adjust CFA when allocating register save area on re-aligned + stack. + +2016-12-21 Joseph Myers + + [BZ #20978] + * nis/nss_nisplus/nisplus-alias.c (_nss_nisplus_getaliasbyname_r): + Compare name == NULL, not name != NULL. + +2016-11-08 Joseph Myers + + [BZ #20790] + * sunrpc/rpc_parse.c (get_prog_declaration): Increase buffer size + to MAXLINESIZE. + * sunrpc/bug20790.x: New file. + * sunrpc/Makefile [$(run-built-tests) = yes] (rpcgen-tests): New + variable. + [$(run-built-tests) = yes] (tests-special): Add $(rpcgen-tests). + [$(run-built-tests) = yes] ($(rpcgen-tests)): New rule. + +2016-10-14 Steve Ellcey + + * sysdeps/ieee754/dbl-64/e_pow.c (checkint) Make conditions explicitly + boolean. + +2017-07-19 DJ Delorie + + [BZ #21654] + * grp/grp-merge.c (libc_hidden_def): Fix cast-after-dereference. + +2017-07-14 DJ Delorie + + [BZ #21654] + * grp/grp_merge.c (__copy_grp): Align char** to minimum pointer + alignment not char alignment. + (__merge_grp): Likewise. + +2017-08-06 H.J. Lu + + [BZ #21871] + * sysdeps/x86/cpu-features.c (init_cpu_features): Set + bit_arch_Use_dl_runtime_resolve_opt only with AVX512F. + +2017-02-27 Florian Weimer + + [BZ #21115] + * sunrpc/clnt_udp.c (clntudp_call): Free ancillary data later. + * sunrpc/Makefile (tests): Add tst-udp-error. + (tst-udp-error): Link against libc.so explicitly. + * sunrpc/tst-udp-error: New file. + +2017-01-24 James Clarke + + * sysdeps/unix/sysv/linux/sh/sh3/ucontext_i.sym: Use new REG_R* + constants instead of the old R* ones. + * sysdeps/unix/sysv/linux/sh/sh4/ucontext_i.sym: Likewise. + * sysdeps/unix/sysv/linux/sh/sys/ucontext.h (NGPREG): Rename... + (NGREG): ... to this, to fit in with other architectures. + (gpregset_t): Use new NGREG macro. + [__USE_GNU]: Remove condition; all architectures other than tile + are unconditional. + (R*): Rename to REG_R*. + +2017-07-26 H.J. Lu + + [BZ #21666] + * misc/regexp.c (loc1): Add __attribute__ ((nocommon)); + (loc2): Likewise. + (locs): Likewise. + +2017-07-12 Szabolcs Nagy + + * sysdeps/aarch64/dl-machine.h (RTLD_START_1): Change _dl_argv to the + hidden __GI__dl_argv symbol. + +2016-09-05 Aurelien Jarno + + * conform/Makefile (conformtest-header-tests): Pass -I. to $(PERL). + (linknamespace-symlists-tests): Likewise. + (linknamespace-header-tests): Likewise. + +2017-07-06 Florian Weimer + H.J. Lu + + [BZ #21609] + * sysdeps/x86_64/Makefile (sysdep-dl-routines): Add tls_get_addr. + (gen-as-const-headers): Add rtld-offsets.sym. + * sysdeps/x86_64/dl-tls.c: New file. + * sysdeps/x86_64/rtld-offsets.sym: Likwise. + * sysdeps/x86_64/tls_get_addr.S: Likewise. + * sysdeps/x86_64/dl-tls.h: Add multiple inclusion guards. + * sysdeps/x86_64/tlsdesc.sym (TI_MODULE_OFFSET): New. + (TI_OFFSET_OFFSET): Likwise. + +2017-06-14 Florian Weimer + + * sysdeps/i386/i686/multiarch/strcspn-c.c: Add IS_IN (libc) guard. + * sysdeps/i386/i686/multiarch/varshift.c: Likewise. + +2017-03-07 Siddhesh Poyarekar + + [BZ #21209] + * elf/rtld.c (process_envvars): Ignore LD_HWCAP_MASK for + AT_SECURE processes. + * sysdeps/generic/unsecvars.h: Add LD_HWCAP_MASK. + +2017-06-19 Florian Weimer + + * elf/rtld.c (audit_list_string): New variable. + (audit_list): Update comment. + (struct audit_list_iter): Define. + (audit_list_iter_init, audit_list_iter_next): New function. + (dl_main): Use struct audit_list_iter to process audit modules. + (process_dl_audit): Call dso_name_valid_for_suid. + (process_envvars): Set audit_list_string instead of calling + process_dl_audit. + +2017-06-19 Florian Weimer + + * elf/rtld.c (SECURE_NAME_LIMIT, SECURE_PATH_LIMIT): Define. + (dso_name_valid_for_suid): New function. + (handle_ld_preload): Likewise. + (dl_main): Call it. Remove alloca. + +2017-06-19 Florian Weimer + + [BZ #21624] + CVE-2017-1000366 + * elf/rtld.c (process_envvars): Ignore LD_LIBRARY_PATH for + __libc_enable_secure. + +2017-02-01 Andreas Schwab + + * sysdeps/m68k/m680x0/m68020/atomic-machine.h + (__arch_compare_and_exchange_val_64_acq, atomic_exchange_acq) + (atomic_exchange_and_add, atomic_add): Add casts to 64 bit asm + operands. + +2017-05-12 Florian Weimer + + [BZ #21386] + * sysdeps/nptl/fork.c (__libc_fork): Remove assertions on the + parent PID. The assertion in the child is incorrect with PID + namespaces. + +2017-06-07 Arjun Shankar + + * sysdeps/unix/sysv/linux/tst-clone2.c: Do not + include test-skeleton.c. + Include support/check.h and support/test-driver.c. + +2016-11-24 Adhemerval Zanella + + * sysdeps/nptl/fork.c (__libc_fork): Remove pid cache setting. + * nptl/allocatestack.c (allocate_stack): Likewise. + (__reclaim_stacks): Likewise. + (setxid_signal_thread): Obtain pid through syscall. + * nptl/nptl-init.c (sigcancel_handler): Likewise. + (sighandle_setxid): Likewise. + * nptl/pthread_cancel.c (pthread_cancel): Likewise. + * sysdeps/unix/sysv/linux/pthread_kill.c (__pthread_kill): Likewise. + * sysdeps/unix/sysv/linux/pthread_sigqueue.c (pthread_sigqueue): + Likewise. + * sysdeps/unix/sysv/linux/createthread.c (create_thread): Likewise. + * sysdeps/unix/sysv/linux/raise.c (raise): Remove old behaviour + comment. + * sysdeps/unix/sysv/linux/getpid.c: Remove file. + * nptl/descr.h (struct pthread): Change comment about pid value. + * nptl/pthread_getattr_np.c (pthread_getattr_np): Remove thread + pid assert. + * sysdeps/unix/sysv/linux/pthread-pids.h (__pthread_initialize_pids): + Do not set pid value. + * nptl_db/td_ta_thr_iter.c (iterate_thread_list): Remove thread + pid cache check. + * nptl_db/td_thr_validate.c (td_thr_validate): Likewise. + * sysdeps/aarch64/nptl/tcb-offsets.sym: Remove pid offset. + * sysdeps/alpha/nptl/tcb-offsets.sym: Likewise. + * sysdeps/arm/nptl/tcb-offsets.sym: Likewise. + * sysdeps/hppa/nptl/tcb-offsets.sym: Likewise. + * sysdeps/i386/nptl/tcb-offsets.sym: Likewise. + * sysdeps/ia64/nptl/tcb-offsets.sym: Likewise. + * sysdeps/m68k/nptl/tcb-offsets.sym: Likewise. + * sysdeps/microblaze/nptl/tcb-offsets.sym: Likewise. + * sysdeps/mips/nptl/tcb-offsets.sym: Likewise. + * sysdeps/nios2/nptl/tcb-offsets.sym: Likewise. + * sysdeps/powerpc/nptl/tcb-offsets.sym: Likewise. + * sysdeps/s390/nptl/tcb-offsets.sym: Likewise. + * sysdeps/sh/nptl/tcb-offsets.sym: Likewise. + * sysdeps/sparc/nptl/tcb-offsets.sym: Likewise. + * sysdeps/tile/nptl/tcb-offsets.sym: Likewise. + * sysdeps/x86_64/nptl/tcb-offsets.sym: Likewise. + * sysdeps/unix/sysv/linux/aarch64/clone.S: Remove pid and tid caching. + * sysdeps/unix/sysv/linux/alpha/clone.S: Likewise. + * sysdeps/unix/sysv/linux/arm/clone.S: Likewise. + * sysdeps/unix/sysv/linux/hppa/clone.S: Likewise. + * sysdeps/unix/sysv/linux/i386/clone.S: Likewise. + * sysdeps/unix/sysv/linux/ia64/clone2.S: Likewise. + * sysdeps/unix/sysv/linux/mips/clone.S: Likewise. + * sysdeps/unix/sysv/linux/nios2/clone.S: Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc32/clone.S: Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S: Likewise. + * sysdeps/unix/sysv/linux/s390/s390-32/clone.S: Likewise. + * sysdeps/unix/sysv/linux/s390/s390-64/clone.S: Likewise. + * sysdeps/unix/sysv/linux/sh/clone.S: Likewise. + * sysdeps/unix/sysv/linux/sparc/sparc32/clone.S: Likewise. + * sysdeps/unix/sysv/linux/sparc/sparc64/clone.S: Likewise. + * sysdeps/unix/sysv/linux/tile/clone.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/clone.S: Likewise. + * sysdeps/unix/sysv/linux/aarch64/vfork.S: Remove pid set and reset. + * sysdeps/unix/sysv/linux/alpha/vfork.S: Likewise. + * sysdeps/unix/sysv/linux/arm/vfork.S: Likewise. + * sysdeps/unix/sysv/linux/i386/vfork.S: Likewise. + * sysdeps/unix/sysv/linux/ia64/vfork.S: Likewise. + * sysdeps/unix/sysv/linux/m68k/clone.S: Likewise. + * sysdeps/unix/sysv/linux/m68k/vfork.S: Likewise. + * sysdeps/unix/sysv/linux/mips/vfork.S: Likewise. + * sysdeps/unix/sysv/linux/nios2/vfork.S: Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S: Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/vfork.S: Likewise. + * sysdeps/unix/sysv/linux/s390/s390-32/vfork.S: Likewise. + * sysdeps/unix/sysv/linux/s390/s390-64/vfork.S: Likewise. + * sysdeps/unix/sysv/linux/sh/vfork.S: Likewise. + * sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S: Likewise. + * sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S: Likewise. + * sysdeps/unix/sysv/linux/tile/vfork.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/vfork.S: Likewise. + * sysdeps/unix/sysv/linux/hppa/pt-vfork.S: Likewise. + * sysdeps/unix/sysv/linux/tst-clone2.c (f): Remove direct pthread + struct access. + (clone_test): Remove function. + (do_test): Rewrite to take in consideration pid is not cached anymore. + +2016-09-26 Adhemerval Zanella + + * sysdeps/unix/sysdep.h (__INTERNAL_SYSCALL0): New macro. + (__INTERNAL_SYSCALL1): Likewise. + (__INTERNAL_SYSCALL2): Likewise. + (__INTERNAL_SYSCALL3): Likewise. + (__INTERNAL_SYSCALL4): Likewise. + (__INTERNAL_SYSCALL5): Likewise. + (__INTERNAL_SYSCALL6): Likewise. + (__INTERNAL_SYSCALL7): Likewise. + (__INTERNAL_SYSCALL_NARGS_X): Likewise. + (__INTERNAL_SYSCALL_NARGS): Likewise. + (__INTERNAL_SYSCALL_DISP): Likewise. + (INTERNAL_SYSCALL_CALL): Likewise. + (__SYSCALL0): Rename to __INLINE_SYSCALL0. + (__SYSCALL1): Rename to __INLINE_SYSCALL1. + (__SYSCALL2): Rename to __INLINE_SYSCALL2. + (__SYSCALL3): Rename to __INLINE_SYSCALL3. + (__SYSCALL4): Rename to __INLINE_SYSCALL4. + (__SYSCALL5): Rename to __INLINE_SYSCALL5. + (__SYSCALL6): Rename to __INLINE_SYSCALL6. + (__SYSCALL7): Rename to __INLINE_SYSCALL7. + (__SYSCALL_NARGS_X): Rename to __INLINE_SYSCALL_NARGS_X. + (__SYSCALL_NARGS): Rename to __INLINE_SYSCALL_NARGS. + (__SYSCALL_DISP): Rename to __INLINE_SYSCALL_DISP. + (__SYSCALL_CALL): Rename to INLINE_SYSCALL_CALL. + (SYSCALL_CANCEL): Replace __SYSCALL_CALL with INLINE_SYSCALL_CALL. + +2017-04-28 H.J. Lu + + [BZ #21396] + * sysdeps/x86/cpu-features.c (init_cpu_features): Set + Prefer_No_AVX512 if AVX512ER isn't available. + * sysdeps/x86/cpu-features.h (bit_arch_Prefer_No_AVX512): New. + (index_arch_Prefer_No_AVX512): Likewise. + * sysdeps/x86_64/multiarch/memcpy.S (__new_memcpy): Don't use + AVX512 version if Prefer_No_AVX512 is set. + * sysdeps/x86_64/multiarch/memcpy_chk.S (__memcpy_chk): + Likewise. + * sysdeps/x86_64/multiarch/memmove.S (__libc_memmove): Likewise. + * sysdeps/x86_64/multiarch/memmove_chk.S (__memmove_chk): + Likewise. + * sysdeps/x86_64/multiarch/mempcpy.S (__mempcpy): Likewise. + * sysdeps/x86_64/multiarch/mempcpy_chk.S (__mempcpy_chk): + Likewise. + * sysdeps/x86_64/multiarch/memset.S (memset): Likewise. + * sysdeps/x86_64/multiarch/memset_chk.S (__memset_chk): + Likewise. + +2017-04-28 H.J. Lu + + * sysdeps/x86/cpu-features.c (init_cpu_features): Set + Prefer_No_VZEROUPPER if AVX512ER is available. + * sysdeps/x86/cpu-features.h + (bit_cpu_AVX512PF): New. + (bit_cpu_AVX512ER): Likewise. + (bit_cpu_AVX512CD): Likewise. + (bit_cpu_AVX512BW): Likewise. + (bit_cpu_AVX512VL): Likewise. + (index_cpu_AVX512PF): Likewise. + (index_cpu_AVX512ER): Likewise. + (index_cpu_AVX512CD): Likewise. + (index_cpu_AVX512BW): Likewise. + (index_cpu_AVX512VL): Likewise. + (reg_AVX512PF): Likewise. + (reg_AVX512ER): Likewise. + (reg_AVX512CD): Likewise. + (reg_AVX512BW): Likewise. + (reg_AVX512VL): Likewise. + +2017-01-05 Joseph Myers + + [BZ #21026] + * sysdeps/unix/sysv/linux/mips/mips64/n64/syscalls.list + (readahead): New syscall entry. + +2017-04-07 H.J. Lu + + [BZ #21258] + * sysdeps/x86_64/dl-trampoline.S (_dl_runtime_resolve_opt): + Define only if _dl_runtime_resolve is defined to + _dl_runtime_resolve_sse_vex. + * sysdeps/x86_64/dl-trampoline.h (_dl_runtime_resolve_opt): + Fallthrough to _dl_runtime_resolve_sse_vex. + +2017-04-03 Mike Frysinger + + [BZ #21253] + * sysdeps/unix/sysv/linux/spawni.c (__spawnix): Increase argv_size + slack space by 32KiB. + +2017-03-31 Slava Barinov + + [BZ #21289] + * io/fts.h (fts_set): Replace __REDIRECT with __REDIRECT_NTH. + +2017-03-20 Mike Frysinger + + [BZ #21275] + * sysdeps/unix/sysv/linux/spawni.c [__ia64__] (CLONE): Rename + __stack to __stackbase. + (STACK): Invert _STACK_GROWS_DOWN and _STACK_GROWS_UP order of + checks so we can include defined(__ia64__) first. + +2017-03-15 John David Anglin + + * sysdeps/hppa/dl-machine.h (DL_STACK_END): Define. + (RTLD_START): Don't record stack end address in _dl_start_user. + +2017-01-30 H.J. Lu + + [BZ #21081] + * sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S + (L(stosb)): Add VZEROUPPER before ret. + +2016-11-28 H.J. Lu + + [BZ #20750] + * sysdeps/x86_64/sysdep.h (JUMPTARGET): Check SHARED instead + of PIC. + +2016-12-31 Florian Weimer + + [BZ #18784] + CVE-2015-5180 + * include/arpa/nameser_compat.h (T_QUERY_A_AND_AAAA): Rename from + T_UNSPEC. Adjust value. + * resolv/nss_dns/dns-host.c (_nss_dns_gethostbyname4_r): Use it. + * resolv/res_query.c (__libc_res_nquery): Likewise. + * resolv/res_mkquery.c (res_nmkquery): Check for out-of-range + QTYPEs. + * resolv/tst-resolv-qtypes.c: New file. + * resolv/Makefile (xtests): Add tst-resolv-qtypes. + (tst-resolv-qtypes): Link against libresolv and libpthread. + +2017-02-02 Siddhesh Poyarekar + + * sysdeps/generic/unsecvars.h: Add GLIBC_TUNABLES. + +2017-01-23 Rajalakshmi Srinivasaraghavan + Steven Munroe + Tulio Magno Quites Machado Filho + + [BZ #20822] + * sysdeps/unix/sysv/linux/powerpc/elision-lock.c + (__lll_lock_elision): Access adapt_count via C11 atomics. + * sysdeps/unix/sysv/linux/powerpc/elision-trylock.c + (__lll_trylock_elision): Likewise. + * sysdeps/unix/sysv/linux/powerpc/elision-unlock.c + (__lll_unlock_elision): Update adapt_count variable inside the + critical section using C11 atomics. + +2016-12-24 Carlos O'Donell + + [BZ #11941] + * elf/dl-close.c (_dl_close): Take dl_load_lock to examine map. + Remove assert (map->l_init_called); if DF_1_NODELETE is set. + * elf/Makefile [ifeq (yes,$(build-shared))] (tests): Add + tst-nodelete-dlclose. + (modules-names): Add tst-nodelete-dlclose-dso and + tst-nodelete-dlclose-plugin. + ($(objpfx)tst-nodelete-dlclose-dso.so): Define. + ($(objpfx)tst-nodelete-dlclose-plugin.so): Define. + ($(objpfx)tst-nodelete-dlclose): Define. + ($(objpfx)tst-nodelete-dlclose.out): Define. + +2016-08-02 Aurelien Jarno + +2016-08-02 Aurelien Jarno + + * sysdeps/alpha/fpu/s_ceil.c (__ceil): Add argument with itself + when it is a NaN. + [_IEEE_FP_INEXACT] Remove. + * sysdeps/alpha/fpu/s_ceilf.c (__ceilf): Likewise. + * sysdeps/alpha/fpu/s_floor.c (__floor): Add argument with itself + when it is a NaN. + [_IEEE_FP_INEXACT] Remove. + * sysdeps/alpha/fpu/s_floorf.c (__floorf): Likewise. + * sysdeps/alpha/fpu/s_rint.c (__rint): Add argument with itself + when it is a NaN. + * sysdeps/alpha/fpu/s_rintf.c (__rintf): Likewise. + * sysdeps/alpha/fpu/s_trunc.c (__trunc): Return the input value + when its absolute value is greater than 0x1.0p52. + [_IEEE_FP_INEXACT] Remove. + * sysdeps/alpha/fpu/s_truncf.c (__truncf): Return the input value + when its absolute value is greater than 0x1.0p23. + [_IEEE_FP_INEXACT] Remove. + +2016-11-30 H.J. Lu + + [BZ #20495] + [BZ #20508] + * sysdeps/x86/cpu-features.c (init_cpu_features): For Intel + processors, set Use_dl_runtime_resolve_slow and set + Use_dl_runtime_resolve_opt if XGETBV suports ECX == 1. + * sysdeps/x86/cpu-features.h (bit_arch_Use_dl_runtime_resolve_opt): + New. + (bit_arch_Use_dl_runtime_resolve_slow): Likewise. + (index_arch_Use_dl_runtime_resolve_opt): Likewise. + (index_arch_Use_dl_runtime_resolve_slow): Likewise. + * sysdeps/x86_64/dl-machine.h (elf_machine_runtime_setup): Use + _dl_runtime_resolve_avx512_opt and _dl_runtime_resolve_avx_opt + if Use_dl_runtime_resolve_opt is set. Use + _dl_runtime_resolve_slow if Use_dl_runtime_resolve_slow is set. + * sysdeps/x86_64/dl-trampoline.S: Include . + (_dl_runtime_resolve_opt): New. Defined for AVX and AVX512. + (_dl_runtime_resolve): Add one for _dl_runtime_resolve_sse_vex. + * sysdeps/x86_64/dl-trampoline.h (_dl_runtime_resolve_avx_slow): + New. + (_dl_runtime_resolve_opt): Likewise. + (_dl_runtime_profile): Define only if _dl_runtime_profile is + defined. + +2016-11-24 Aurelien Jarno + + * sysdeps/x86_64/memcpy_chk.S (__memcpy_chk): Check for SHARED + instead of PIC. + +2016-11-23 Matthew Fortune + Maciej W. Rozycki + + * sysdeps/mips/mips32/crti.S (_init): Add `.insn' pseudo-op at + `.Lno_weak_fn' label. + * sysdeps/mips/mips64/n32/crti.S (_init): Likewise. + * sysdeps/mips/mips64/n64/crti.S (_init): Likewise. + +2016-11-22 Adhemerval Zanella + + [BZ #20847] + * posix/execvpe.c (maybe_script_execute): Remove write past allocated + array bounds. + (__execvpe): Likewise. + +2016-11-15 Denis Kaganovich + Magnus Granberg + Mike Frysinger + + [BZ #20662] + * configure.ac (libc_cv_predef_stack_protector): Also check for + __stack_chk_fail_local symbols. + * configure: Regenerated. + +2016-11-03 Joseph Myers + + * conform/Makefile ($(linknamespace-header-tests)): Also depend on + $(linknamespace-symlists-tests). + +2016-11-06 Aurelien Jarno + + * iconv/gconv.h (__gconv_info): Define __data element using a + zero-length array. + +2016-10-25 Joseph Myers + + * sysdeps/powerpc/powerpc32/power6/memset.S (memset): Use cmplwi + instead of cmpli. + * sysdeps/powerpc/powerpc64/power6/memset.S (memset): Use cmpldi + instead of cmpli. + +2016-10-24 Adhemerval Zanella + + * sysdeps/unix/sysv/linux/pread.c (__libc_pread): Use SYSCALL_LL_PRW. + * sysdeps/unix/sysv/linux/pwrite.c (__libc_pwrite): Likewise. + * sysdeps/unix/sysv/linux/pread64.c (__libc_pread64): Use + SYSCALL_LL64_PRW. + * sysdeps/unix/sysv/linux/pwrite64.c (__libc_pwrite64): Likewise. + * sysdeps/unix/sysv/linux/sh/kernel-features.h: Define + __ASSUME_PRW_DUMMY_ARG. + * sysdeps/unix/sysv/linux/sh/pread.c: Remove file. + * sysdeps/unix/sysv/linux/sh/pread64.c: Likewise. + * sysdeps/unix/sysv/linux/sh/pwrite.c: Likewise. + * sysdeps/unix/sysv/linux/sh/pwrite64.c: Likewise. + * sysdeps/unix/sysv/linux/sysdep.h: Define SYSCALL_LL_PRW and + SYSCALL_LL_PRW64 based on __ASSUME_PRW_DUMMY_ARG. + +2016-10-05 Tulio Magno Quites Machado Filho + + * sysdeps/powerpc/fpu/libm-test-ulps: Regenerated. + +2016-09-20 Adhemerval Zanella + + * sysdeps/unix/sysv/linux/spawni.c (__spawnix): Correctly block and unblock + all signals when executing the clone vfork child. + (SIGALL_SET): Remove macro. + + * nptl/Makefile (tests): Add tst-exec5. + * nptl/tst-exec5.c: New file. + * sysdeps/unix/sysv/linux/spawni.c (__spawni): Correctly enable and disable + asynchronous cancellation. + +2016-09-19 Tulio Magno Quites Machado Filho + + [BZ #20615] + * sysdeps/powerpc/powerpc32/power9/multiarch/Implies: Replace + fpu directory by non-fpu. + * sysdeps/powerpc/powerpc64/power9/fpu/Implies: Remove dependency + on non-fpu directory from a fpu directory. + +2016-09-02 Roland McGrath + + * sysdeps/arm/nacl/libc.abilist: Add GLIBC_2.24 A. + + * sysdeps/nacl/dup.c: Add libc_hidden_def. + +2016-09-02 Roland McGrath + + * sysdeps/posix/wait3.c: Don't treat STAT_LOC as a union, since it's + not any more. + +2016-09-02 Roland McGrath + + * sysdeps/nacl/clock.c (clock): nacl_abi_clock_t -> nacl_irt_clock_t + +2016-08-17 Florian Weimer + + Reduce time to expected nptl/tst-once5 failure. + * nptl/tst-once5.cc (TIMEOUT): Define. + +2016-08-18 Florian Weimer + + [BZ #16907] + * argp/argp.h: Switch to __BEGIN_DECLS and __END_DECLS. + (__THROW, __NTH, __attribute__, __restrict): Remove definitions. + * argp/argp-fmtstream.h: Add __BEGIN_DECLS and __END_DECLS. + (__attribute__): Remove definition. + +2016-08-15 Andreas Schwab + + [BZ #20435] + * sysdeps/unix/sysv/linux/arm/setcontext.S (__startcontext): Mark + as .cantunwind. + +2016-08-17 Florian Weimer + + [BZ #20452] + Avoid additional copies of objects in libc.a in static libraries. + * sysdeps/ia64/nptl/Makefile (libpthread-shared-only-routines): + Add ptw-sysdep, ptw-sigblock, ptw-sigprocmask. + * sysdeps/mips/Makefile (librt-shared-only-routines): Add + rt-sysdep. + * sysdeps/mips/nptl/Makefile (libpthread-shared-only-routines): + Add nptl-sysdep. + * sysdeps/s390/nptl/Makefile (libpthread-shared-only-routines): + Add ptw-sysdep. + * sysdeps/unix/alpha/Makefile (librt-shared-only-routines): Add + rt-sysdep. + * sysdeps/unix/sysv/linux/alpha/Makefile + (libpthread-shared-only-routines): Add ptw-sysdep, + ptw-sigprocmask, ptw-rt_sigaction. + * sysdeps/unix/sysv/linux/ia64/Makefile + (librt-shared-only-routines): Add rt-sysdep. + * sysdeps/unix/sysv/linux/i386/Makefile + (libpthread-shared-only-routines): Add libc-do-syscall. + * sysdeps/unix/sysv/linux/microblaze/Makefile + (libpthread-shared-only-routines): Add sysdep. + * sysdeps/unix/sysv/linux/powerpc/Makefile + (librt-shared-only-routines): Add rt-sysdep. + (libpthread-shared-only-routines): Add sysdep. + * sysdeps/unix/sysv/linux/s390/Makefile + (librt-shared-only-routines): Add rt-sysdep. + * sysdeps/unix/sysv/linux/sparc/Makefile + (librt-shared-only-routines): Add rt-sysdep. + (libpthread-shared-only-routines): Add sysdep. + * sysdeps/unix/sysv/linux/tile/Makefile + (libpthread-shared-only-routines): Likewise. + +2016-08-05 Aurelien Jarno + + * sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/Makefile + [$(subdir) = math && $(have-as-vis3) = yes] (libm-sysdep_routines): + Remove s_fdimf-vis3, s_fdim-vis3. + * sysdeps/sparc/sparc32/fpu/s_fdim.S: Delete file. + * sysdeps/sparc/sparc32/fpu/s_fdimf.S: Likewise. + * sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdim-vis3.S: Likewise. + * sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdim.S: Likewise. + * sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdimf-vis3.S: Likewise. + * sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdimf.S: Likewise. + * sysdeps/sparc/sparc32/sparcv9/fpu/s_fdim.S: Likewise. + * sysdeps/sparc/sparc32/sparcv9/fpu/s_fdimf.S: Likewise. + * sysdeps/sparc/sparc64/fpu/s_fdim.S: Likewise. + * sysdeps/sparc/sparc64/fpu/s_fdimf.S: Likewise. + +2016-08-02 David S. Miller + + * sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_nearbyint-vis3.S + (__nearbyint_vis3): Don't check for sNaN before float register is + loaded with the incoming argument. + * sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_nearbyintf-vis3.S + (__nearbyintf_vis3): Likewise. + * sysdeps/sparc/sparc32/sparcv9/fpu/s_nearbyint.S (__nearbyint): + Likewise. + * sysdeps/sparc/sparc32/sparcv9/fpu/s_nearbyintf.S (__nearbyintf): + Likewise. + +2016-08-03 Aurelien Jarno + + * sysdeps/powerpc/ifunc-sel.h (ifunc_sel): Replace beqlr instructions + by beq instructions jumping to the end of the function. + * sysdeps/powerpc/ifunc-sel.h (ifunc_sel): Add "11", "12", "cr0" to the + clobber list. Use "i" constraint instead of "X". + (ifunc_one): Add "12" to the clobber list. Use "i" constraint instead + of "X". + +2016-08-04 Carlos O'Donell + + * po/de.po: Update from Translation Project. + * po/fi.po: Likewise. + * po/sv.po: Likewise. + +2016-08-02 Florian Weimer + + [BZ #20370] + * malloc/arena.c (get_free_list): Update comment. Assert that + arenas on the free list have no attached threads. + (remove_from_free_list): New function. + (reused_arena): Call it. + +2016-08-04 Florian Weimer + + Use sysdep.o from libc.a in static libraries. + * sysdeps/unix/sysv/linux/i386/Makefile + (libpthread-shared-only-routines): Add sysdep. + (librt-shared-only-routines): Likewise. + 2016-08-01 Carlos O'Donell * version.h (RELEASE): Set to "stable" diff --git a/Makeconfig b/Makeconfig index 03fd89c13e..ee379f5852 100644 --- a/Makeconfig +++ b/Makeconfig @@ -394,6 +394,9 @@ ifndef after-link after-link = endif +# Additional libraries to link into every test. +link-extra-libs-tests = $(libsupport) + # Command for linking PIE programs with the C library. ifndef +link-pie +link-pie-before-libc = $(CC) -pie -Wl,-O1 -nostdlib -nostartfiles -o $@ \ @@ -503,7 +506,7 @@ link-libc = $(link-libc-rpath-link) $(link-libc-before-gnulib) $(gnulib) link-libc-tests = $(link-libc-tests-rpath-link) \ $(link-libc-before-gnulib) $(gnulib-tests) # This is how to find at build-time things that will be installed there. -rpath-dirs = math elf dlfcn nss nis rt resolv crypt mathvec +rpath-dirs = math elf dlfcn nss nis rt resolv crypt mathvec support rpath-link = \ $(common-objdir):$(subst $(empty) ,:,$(patsubst ../$(subdir),.,$(rpath-dirs:%=$(common-objpfx)%))) else @@ -850,7 +853,7 @@ libio-include = -I$(..)libio # List of non-library modules that we build. built-modules = iconvprogs iconvdata ldconfig lddlibc4 libmemusage \ libSegFault libpcprofile librpcsvc locale-programs \ - memusagestat nonlib nscd extramodules libnldbl + memusagestat nonlib nscd extramodules libnldbl libsupport in-module = $(subst -,_,$(firstword $(libof-$(basename $(@F))) \ $(libof-$( using `glibc' in the "product" field. +Version 2.24.1 + +Security related changes: + +* On ARM EABI (32-bit), generating a backtrace for execution contexts which + have been created with makecontext could fail to terminate due to a + missing .cantunwind annotation. This has been observed to lead to a hang + (denial of service) in some Go applications compiled with gccgo. Reported + by Andreas Schwab. (CVE-2016-6323) + +* The DNS stub resolver functions would crash due to a NULL pointer + dereference when processing a query with a valid DNS question type which + was used internally in the implementation. The stub resolver now uses a + question type which is outside the range of valid question type values. + (CVE-2015-5180) + +* CVE-2017-15670: The glob function, when invoked with GLOB_TILDE, suffered + from a one-byte overflow during ~ operator processing (either on the stack + or the heap, depending on the length of the user name). + +* CVE-2017-15671: The glob function, when invoked with GLOB_TILDE, + would sometimes fail to free memory allocated during ~ operator + processing, leading to a memory leak and, potentially, to a denial + of service. + +* CVE-2017-15804: The glob function, when invoked with GLOB_TILDE and + without GLOB_NOESCAPE, could write past the end of a buffer while + unescaping user names. Reported by Tim Rühsen. + +* CVE-2017-1000408: Incorrect array size computation in _dl_init_paths leads + to the allocation of too much memory. (This is not a security bug per se, + it is mentioned here only because of the CVE assignment.) Reported by + Qualys. + +* CVE-2017-1000409: Buffer overflow in _dl_init_paths due to miscomputation + of the number of search path components. (This is not a security + vulnerability per se because no trust boundary is crossed if the fix for + CVE-2017-1000366 has been applied, but it is mentioned here only because + of the CVE assignment.) Reported by Qualys. + + CVE-2017-16997: Incorrect handling of RPATH or RUNPATH containing $ORIGIN + for AT_SECURE or SUID binaries could be used to load libraries from the + current directory. + + CVE-2018-1000001: Buffer underflow in realpath function when getcwd function + succeeds without returning an absolute path due to unexpected behaviour + of the Linux kernel getcwd syscall. Reported by halfdog. + +The following bugs are resolved with this release: + + [20790] Fix rpcgen buffer overrun + [20978] Fix strlen on null pointer in nss_nisplus + [21209] Ignore and remove LD_HWCAP_MASK for AT_SECURE programs + [21265] x86-64: Use fxsave/xsave/xsavec in _dl_runtime_resolve + [21289] Fix symbol redirect for fts_set + [21386] Assertion in fork for distinct parent PID is incorrect + [21609] x86-64: Align the stack in __tls_get_addr + [21624] Unsafe alloca allows local attackers to alias stack and heap (CVE-2017-1000366) + [21654] nss: Fix invalid cast in group merging + [22679] getcwd(3) can succeed without returning an absolute path + (CVE-2018-1000001) + Version 2.24 * The minimum Linux kernel version that this version of the GNU C Library diff --git a/Rules b/Rules index 8306d36a07..a981965d2b 100644 --- a/Rules +++ b/Rules @@ -149,6 +149,7 @@ endif ifneq "$(strip $(binaries-shared-tests))" "" $(addprefix $(objpfx),$(binaries-shared-tests)): %: %.o \ + $(link-extra-libs-tests) \ $(sort $(filter $(common-objpfx)lib%,$(link-libc))) \ $(addprefix $(csu-objpfx),start.o) $(+preinit) $(+postinit) $(+link-tests) @@ -156,6 +157,7 @@ endif ifneq "$(strip $(binaries-pie-tests))" "" $(addprefix $(objpfx),$(binaries-pie-tests)): %: %.o \ + $(link-extra-libs-tests) \ $(sort $(filter $(common-objpfx)lib%,$(link-libc))) \ $(addprefix $(csu-objpfx),start.o) $(+preinit) $(+postinit) $(+link-pie-tests) @@ -177,6 +179,7 @@ endif ifneq "$(strip $(binaries-static-tests))" "" $(addprefix $(objpfx),$(binaries-static-tests)): %: %.o \ + $(link-extra-libs-tests) \ $(sort $(filter $(common-objpfx)lib%,$(link-libc-static-tests))) \ $(addprefix $(csu-objpfx),start.o) $(+preinit) $(+postinit) $(+link-static-tests) diff --git a/argp/argp-fmtstream.h b/argp/argp-fmtstream.h index bdeaa54dc2..e8c5797f38 100644 --- a/argp/argp-fmtstream.h +++ b/argp/argp-fmtstream.h @@ -29,21 +29,6 @@ #include #include -#ifndef __attribute__ -/* This feature is available in gcc versions 2.5 and later. */ -# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || \ - defined __STRICT_ANSI__ -# define __attribute__(Spec) /* empty */ -# endif -/* The __-protected variants of `format' and `printf' attributes - are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */ -# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) || \ - defined __STRICT_ANSI__ -# define __format__ format -# define __printf__ printf -# endif -#endif - #if defined (__GNU_LIBRARY__) && defined (HAVE_LINEWRAP_H) /* line_wrap_stream is available, so use that. */ #define ARGP_FMTSTREAM_USE_LINEWRAP @@ -111,6 +96,8 @@ struct argp_fmtstream typedef struct argp_fmtstream *argp_fmtstream_t; +__BEGIN_DECLS + /* Return an argp_fmtstream that outputs to STREAM, and which prefixes lines written on it with LMARGIN spaces and limits them to RMARGIN columns total. If WMARGIN >= 0, words that extend past RMARGIN are wrapped by @@ -297,6 +284,8 @@ __argp_fmtstream_point (argp_fmtstream_t __fs) #endif /* __OPTIMIZE__ */ +__END_DECLS + #endif /* ARGP_FMTSTREAM_USE_LINEWRAP */ #endif /* argp-fmtstream.h */ diff --git a/argp/argp.h b/argp/argp.h index e67bbef739..7cb5a69f08 100644 --- a/argp/argp.h +++ b/argp/argp.h @@ -28,48 +28,12 @@ #define __need_error_t #include -#ifndef __THROW -# define __THROW -#endif -#ifndef __NTH -# define __NTH(fct) fct __THROW -#endif - -#ifndef __attribute__ -/* This feature is available in gcc versions 2.5 and later. */ -# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || \ - defined __STRICT_ANSI__ -# define __attribute__(Spec) /* empty */ -# endif -/* The __-protected variants of `format' and `printf' attributes - are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */ -# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) || \ - defined __STRICT_ANSI__ -# define __format__ format -# define __printf__ printf -# endif -#endif - -/* GCC 2.95 and later have "__restrict"; C99 compilers have - "restrict", and "configure" may have defined "restrict". */ -#ifndef __restrict -# if ! (2 < __GNUC__ || (2 == __GNUC__ && 95 <= __GNUC_MINOR__)) -# if defined restrict || 199901L <= __STDC_VERSION__ -# define __restrict restrict -# else -# define __restrict -# endif -# endif -#endif - #ifndef __error_t_defined typedef int error_t; # define __error_t_defined #endif -#ifdef __cplusplus -extern "C" { -#endif +__BEGIN_DECLS /* A description of a particular option. A pointer to an array of these is passed in the OPTIONS field of an argp structure. Each option @@ -590,8 +554,6 @@ __NTH (__option_is_end (const struct argp_option *__opt)) # endif #endif /* Use extern inlines. */ -#ifdef __cplusplus -} -#endif +__END_DECLS #endif /* argp.h */ diff --git a/configure b/configure index 17625e1041..9b5a486048 100755 --- a/configure +++ b/configure @@ -6289,12 +6289,14 @@ echo >&5 "libc_undefs='$libc_undefs'" # symbols (resolved by the linker), so filter out unknown symbols. # This will fail to produce the correct result if the compiler # defaults to -fstack-protector but this produces an undefined symbol -# other than __stack_chk_fail. However, compilers like that have not -# been encountered in practice. -libc_undefs=`echo "$libc_undefs" | egrep '^(foobar|__stack_chk_fail)$'` +# other than __stack_chk_fail or __stack_chk_fail_local. However, +# compilers like that have not been encountered in practice. +libc_undefs=`echo "$libc_undefs" | \ + egrep '^(foobar|__stack_chk_fail|__stack_chk_fail_local)$'` case "$libc_undefs" in foobar) libc_cv_predef_stack_protector=no ;; '__stack_chk_fail +foobar'|'__stack_chk_fail_local foobar') libc_cv_predef_stack_protector=yes ;; *) as_fn_error $? "unexpected symbols in test: $libc_undefs" "$LINENO" 5 ;; esac diff --git a/configure.ac b/configure.ac index 33bcd62180..8277d9f727 100644 --- a/configure.ac +++ b/configure.ac @@ -1626,12 +1626,14 @@ echo >&AS_MESSAGE_LOG_FD "libc_undefs='$libc_undefs'" # symbols (resolved by the linker), so filter out unknown symbols. # This will fail to produce the correct result if the compiler # defaults to -fstack-protector but this produces an undefined symbol -# other than __stack_chk_fail. However, compilers like that have not -# been encountered in practice. -libc_undefs=`echo "$libc_undefs" | egrep '^(foobar|__stack_chk_fail)$'` +# other than __stack_chk_fail or __stack_chk_fail_local. However, +# compilers like that have not been encountered in practice. +libc_undefs=`echo "$libc_undefs" | \ + egrep '^(foobar|__stack_chk_fail|__stack_chk_fail_local)$'` case "$libc_undefs" in foobar) libc_cv_predef_stack_protector=no ;; '__stack_chk_fail +foobar'|'__stack_chk_fail_local foobar') libc_cv_predef_stack_protector=yes ;; *) AC_MSG_ERROR([unexpected symbols in test: $libc_undefs]) ;; esac], diff --git a/conform/Makefile b/conform/Makefile index 32a0937b06..7883624c81 100644 --- a/conform/Makefile +++ b/conform/Makefile @@ -196,13 +196,13 @@ $(conformtest-header-tests): $(objpfx)%/conform.out: \ conformtest.pl $(conformtest-headers-data) (set -e; std_hdr=$*; std=$${std_hdr%%/*}; hdr=$${std_hdr#*/}; \ mkdir -p $(@D)/scratch; \ - $(PERL) conformtest.pl --tmpdir=$(@D)/scratch --cc='$(CC)' \ + $(PERL) -I. conformtest.pl --tmpdir=$(@D)/scratch --cc='$(CC)' \ --flags='$(conformtest-cc-flags)' --standard=$$std \ --headers=$$hdr > $@); \ $(evaluate-test) $(linknamespace-symlists-tests): $(objpfx)symlist-%: list-header-symbols.pl - $(PERL) -w $< --tmpdir=$(objpfx) --cc='$(CC)' \ + $(PERL) -I. -w $< --tmpdir=$(objpfx) --cc='$(CC)' \ --flags='$(conformtest-cc-flags)' --standard=$* \ --headers="$(strip $(conformtest-headers-$*))" \ > $@ 2> $@.err; \ @@ -229,10 +229,11 @@ $(linknamespace-symlist-stdlibs-tests): $(objpfx)symlist-stdlibs-%: \ $(linknamespace-header-tests): $(objpfx)%/linknamespace.out: \ linknamespace.pl \ + $(linknamespace-symlists-tests) \ $(linknamespace-symlist-stdlibs-tests) (set -e; std_hdr=$*; std=$${std_hdr%%/*}; hdr=$${std_hdr#*/}; \ mkdir -p $(@D)/scratch; \ - $(PERL) -w $< --tmpdir=$(@D)/scratch --cc='$(CC)' \ + $(PERL) -I. -w $< --tmpdir=$(@D)/scratch --cc='$(CC)' \ --flags='$(conformtest-cc-flags)' --standard=$$std \ --stdsyms=$(objpfx)symlist-$$std --header=$$hdr \ --libsyms=$(objpfx)symlist-stdlibs-$$std \ diff --git a/elf/Makefile b/elf/Makefile index 593403c640..847a012f84 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -149,7 +149,8 @@ tests += loadtest restest1 preloadtest loadfail multiload origtest resolvfail \ tst-nodelete) \ tst-initorder tst-initorder2 tst-relsort1 tst-null-argv \ tst-ptrguard1 tst-tlsalign tst-tlsalign-extern tst-nodelete-opened \ - tst-nodelete2 tst-audit11 tst-audit12 tst-dlsym-error + tst-nodelete2 tst-audit11 tst-audit12 tst-dlsym-error \ + tst-nodelete-dlclose # reldep9 ifeq ($(build-hardcoded-path-in-tests),yes) tests += tst-dlopen-aout @@ -223,7 +224,8 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ tst-array5dep tst-null-argv-lib \ tst-tlsalign-lib tst-nodelete-opened-lib tst-nodelete2mod \ tst-audit11mod1 tst-audit11mod2 tst-auditmod11 \ - tst-audit12mod1 tst-audit12mod2 tst-audit12mod3 tst-auditmod12 + tst-audit12mod1 tst-audit12mod2 tst-audit12mod3 tst-auditmod12 \ + tst-nodelete-dlclose-dso tst-nodelete-dlclose-plugin ifeq (yes,$(have-mtls-dialect-gnu2)) tests += tst-gnu2-tls1 modules-names += tst-gnu2-tls1mod @@ -1267,3 +1269,12 @@ $(objpfx)tst-ldconfig-X.out : tst-ldconfig-X.sh $(objpfx)ldconfig $(evaluate-test) $(objpfx)tst-dlsym-error: $(libdl) + +# The application depends on the DSO, and the DSO loads the plugin. +# The plugin also depends on the DSO. This creates the circular +# dependency via dlopen that we're testing to make sure works. +$(objpfx)tst-nodelete-dlclose-dso.so: $(libdl) +$(objpfx)tst-nodelete-dlclose-plugin.so: $(objpfx)tst-nodelete-dlclose-dso.so +$(objpfx)tst-nodelete-dlclose: $(objpfx)tst-nodelete-dlclose-dso.so +$(objpfx)tst-nodelete-dlclose.out: $(objpfx)tst-nodelete-dlclose-dso.so \ + $(objpfx)tst-nodelete-dlclose-plugin.so diff --git a/elf/dl-close.c b/elf/dl-close.c index 687d7de874..9f93ab7628 100644 --- a/elf/dl-close.c +++ b/elf/dl-close.c @@ -805,19 +805,37 @@ _dl_close (void *_map) { struct link_map *map = _map; - /* First see whether we can remove the object at all. */ + /* We must take the lock to examine the contents of map and avoid + concurrent dlopens. */ + __rtld_lock_lock_recursive (GL(dl_load_lock)); + + /* At this point we are guaranteed nobody else is touching the list of + loaded maps, but a concurrent dlclose might have freed our map + before we took the lock. There is no way to detect this (see below) + so we proceed assuming this isn't the case. First see whether we + can remove the object at all. */ if (__glibc_unlikely (map->l_flags_1 & DF_1_NODELETE)) { - assert (map->l_init_called); /* Nope. Do nothing. */ + __rtld_lock_unlock_recursive (GL(dl_load_lock)); return; } + /* At present this is an unreliable check except in the case where the + caller has recursively called dlclose and we are sure the link map + has not been freed. In a non-recursive dlclose the map itself + might have been freed and this access is potentially a data race + with whatever other use this memory might have now, or worse we + might silently corrupt memory if it looks enough like a link map. + POSIX has language in dlclose that appears to guarantee that this + should be a detectable case and given that dlclose should be threadsafe + we need this to be a reliable detection. + This is bug 20990. */ if (__builtin_expect (map->l_direct_opencount, 1) == 0) - GLRO(dl_signal_error) (0, map->l_name, NULL, N_("shared object not open")); - - /* Acquire the lock. */ - __rtld_lock_lock_recursive (GL(dl_load_lock)); + { + __rtld_lock_unlock_recursive (GL(dl_load_lock)); + _dl_signal_error (0, map->l_name, NULL, N_("shared object not open")); + } _dl_close_worker (map, false); diff --git a/elf/dl-load.c b/elf/dl-load.c index c0d6249373..1f774e139f 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -103,7 +104,9 @@ static size_t ncapstr attribute_relro; static size_t max_capstrlen attribute_relro; -/* Get the generated information about the trusted directories. */ +/* Get the generated information about the trusted directories. Use + an array of concatenated strings to avoid relocations. See + gen-trusted-dirs.awk. */ #include "trusted-dirs.h" static const char system_dirs[] = SYSTEM_DIRS; @@ -111,9 +114,7 @@ static const size_t system_dirs_len[] = { SYSTEM_DIRS_LEN }; -#define nsystem_dirs_len \ - (sizeof (system_dirs_len) / sizeof (system_dirs_len[0])) - +#define nsystem_dirs_len array_length (system_dirs_len) static bool is_trusted_path (const char *path, size_t len) @@ -433,31 +434,40 @@ fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep, { char *cp; size_t nelems = 0; - char *to_free; while ((cp = __strsep (&rpath, sep)) != NULL) { struct r_search_path_elem *dirp; + char *to_free = NULL; + size_t len = 0; - to_free = cp = expand_dynamic_string_token (l, cp, 1); + /* `strsep' can pass an empty string. */ + if (*cp != '\0') + { + to_free = cp = expand_dynamic_string_token (l, cp, 1); - size_t len = strlen (cp); + /* expand_dynamic_string_token can return NULL in case of empty + path or memory allocation failure. */ + if (cp == NULL) + continue; - /* `strsep' can pass an empty string. This has to be - interpreted as `use the current directory'. */ - if (len == 0) - { - static const char curwd[] = "./"; - cp = (char *) curwd; - } + /* Compute the length after dynamic string token expansion and + ignore empty paths. */ + len = strlen (cp); + if (len == 0) + { + free (to_free); + continue; + } - /* Remove trailing slashes (except for "/"). */ - while (len > 1 && cp[len - 1] == '/') - --len; + /* Remove trailing slashes (except for "/"). */ + while (len > 1 && cp[len - 1] == '/') + --len; - /* Now add one if there is none so far. */ - if (len > 0 && cp[len - 1] != '/') - cp[len++] = '/'; + /* Now add one if there is none so far. */ + if (len > 0 && cp[len - 1] != '/') + cp[len++] = '/'; + } /* Make sure we don't use untrusted directories if we run SUID. */ if (__glibc_unlikely (check_trusted) && !is_trusted_path (cp, len)) @@ -621,6 +631,14 @@ decompose_rpath (struct r_search_path_struct *sps, necessary. */ free (copy); + /* There is no path after expansion. */ + if (result[0] == NULL) + { + free (result); + sps->dirs = (struct r_search_path_elem **) -1; + return false; + } + sps->dirs = result; /* The caller will change this value if we haven't used a real malloc. */ sps->malloced = 1; @@ -688,9 +706,8 @@ _dl_init_paths (const char *llp) + ncapstr * sizeof (enum r_dir_status)) / sizeof (struct r_search_path_elem)); - rtld_search_dirs.dirs[0] = (struct r_search_path_elem *) - malloc ((sizeof (system_dirs) / sizeof (system_dirs[0])) - * round_size * sizeof (struct r_search_path_elem)); + rtld_search_dirs.dirs[0] = malloc (nsystem_dirs_len * round_size + * sizeof (*rtld_search_dirs.dirs[0])); if (rtld_search_dirs.dirs[0] == NULL) { errstring = N_("cannot create cache for search path"); @@ -776,37 +793,14 @@ _dl_init_paths (const char *llp) if (llp != NULL && *llp != '\0') { - size_t nllp; - const char *cp = llp; - char *llp_tmp; - -#ifdef SHARED - /* Expand DSTs. */ - size_t cnt = DL_DST_COUNT (llp, 1); - if (__glibc_likely (cnt == 0)) - llp_tmp = strdupa (llp); - else - { - /* Determine the length of the substituted string. */ - size_t total = DL_DST_REQUIRED (l, llp, strlen (llp), cnt); - - /* Allocate the necessary memory. */ - llp_tmp = (char *) alloca (total + 1); - llp_tmp = _dl_dst_substitute (l, llp, llp_tmp, 1); - } -#else - llp_tmp = strdupa (llp); -#endif + char *llp_tmp = strdupa (llp); /* Decompose the LD_LIBRARY_PATH contents. First determine how many elements it has. */ - nllp = 1; - while (*cp) - { - if (*cp == ':' || *cp == ';') - ++nllp; - ++cp; - } + size_t nllp = 1; + for (const char *cp = llp_tmp; *cp != '\0'; ++cp) + if (*cp == ':' || *cp == ';') + ++nllp; env_path_list.dirs = (struct r_search_path_elem **) malloc ((nllp + 1) * sizeof (struct r_search_path_elem *)); diff --git a/elf/rtld.c b/elf/rtld.c index 647661ca45..8f56d6edd3 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -99,14 +99,121 @@ uintptr_t __pointer_chk_guard_local strong_alias (__pointer_chk_guard_local, __pointer_chk_guard) #endif +/* Length limits for names and paths, to protect the dynamic linker, + particularly when __libc_enable_secure is active. */ +#ifdef NAME_MAX +# define SECURE_NAME_LIMIT NAME_MAX +#else +# define SECURE_NAME_LIMIT 255 +#endif +#ifdef PATH_MAX +# define SECURE_PATH_LIMIT PATH_MAX +#else +# define SECURE_PATH_LIMIT 1024 +#endif + +/* Check that AT_SECURE=0, or that the passed name does not contain + directories and is not overly long. Reject empty names + unconditionally. */ +static bool +dso_name_valid_for_suid (const char *p) +{ + if (__glibc_unlikely (__libc_enable_secure)) + { + /* Ignore pathnames with directories for AT_SECURE=1 + programs, and also skip overlong names. */ + size_t len = strlen (p); + if (len >= SECURE_NAME_LIMIT || memchr (p, '/', len) != NULL) + return false; + } + return *p != '\0'; +} -/* List of auditing DSOs. */ +/* LD_AUDIT variable contents. Must be processed before the + audit_list below. */ +const char *audit_list_string; + +/* Cyclic list of auditing DSOs. audit_list->next is the first + element. */ static struct audit_list { const char *name; struct audit_list *next; } *audit_list; +/* Iterator for audit_list_string followed by audit_list. */ +struct audit_list_iter +{ + /* Tail of audit_list_string still needing processing, or NULL. */ + const char *audit_list_tail; + + /* The list element returned in the previous iteration. NULL before + the first element. */ + struct audit_list *previous; + + /* Scratch buffer for returning a name which is part of + audit_list_string. */ + char fname[SECURE_NAME_LIMIT]; +}; + +/* Initialize an audit list iterator. */ +static void +audit_list_iter_init (struct audit_list_iter *iter) +{ + iter->audit_list_tail = audit_list_string; + iter->previous = NULL; +} + +/* Iterate through both audit_list_string and audit_list. */ +static const char * +audit_list_iter_next (struct audit_list_iter *iter) +{ + if (iter->audit_list_tail != NULL) + { + /* First iterate over audit_list_string. */ + while (*iter->audit_list_tail != '\0') + { + /* Split audit list at colon. */ + size_t len = strcspn (iter->audit_list_tail, ":"); + if (len > 0 && len < sizeof (iter->fname)) + { + memcpy (iter->fname, iter->audit_list_tail, len); + iter->fname[len] = '\0'; + } + else + /* Do not return this name to the caller. */ + iter->fname[0] = '\0'; + + /* Skip over the substring and the following delimiter. */ + iter->audit_list_tail += len; + if (*iter->audit_list_tail == ':') + ++iter->audit_list_tail; + + /* If the name is valid, return it. */ + if (dso_name_valid_for_suid (iter->fname)) + return iter->fname; + /* Otherwise, wrap around and try the next name. */ + } + /* Fall through to the procesing of audit_list. */ + } + + if (iter->previous == NULL) + { + if (audit_list == NULL) + /* No pre-parsed audit list. */ + return NULL; + /* Start of audit list. The first list element is at + audit_list->next (cyclic list). */ + iter->previous = audit_list->next; + return iter->previous->name; + } + if (iter->previous == audit_list) + /* Cyclic list wrap-around. */ + return NULL; + iter->previous = iter->previous->next; + return iter->previous->name; +} + #ifndef HAVE_INLINED_SYSCALLS /* Set nonzero during loading and initialization of executable and libraries, cleared before the executable's entry point runs. This @@ -730,6 +837,42 @@ static const char *preloadlist attribute_relro; /* Nonzero if information about versions has to be printed. */ static int version_info attribute_relro; +/* The LD_PRELOAD environment variable gives list of libraries + separated by white space or colons that are loaded before the + executable's dependencies and prepended to the global scope list. + (If the binary is running setuid all elements containing a '/' are + ignored since it is insecure.) Return the number of preloads + performed. */ +unsigned int +handle_ld_preload (const char *preloadlist, struct link_map *main_map) +{ + unsigned int npreloads = 0; + const char *p = preloadlist; + char fname[SECURE_PATH_LIMIT]; + + while (*p != '\0') + { + /* Split preload list at space/colon. */ + size_t len = strcspn (p, " :"); + if (len > 0 && len < sizeof (fname)) + { + memcpy (fname, p, len); + fname[len] = '\0'; + } + else + fname[0] = '\0'; + + /* Skip over the substring and the following delimiter. */ + p += len; + if (*p != '\0') + ++p; + + if (dso_name_valid_for_suid (fname)) + npreloads += do_preload (fname, main_map, "LD_PRELOAD"); + } + return npreloads; +} + static void dl_main (const ElfW(Phdr) *phdr, ElfW(Word) phnum, @@ -1257,11 +1400,13 @@ of this helper program; chances are you did not intend to run this program.\n\ GL(dl_rtld_map).l_tls_modid = _dl_next_tls_modid (); /* If we have auditing DSOs to load, do it now. */ - if (__glibc_unlikely (audit_list != NULL)) + bool need_security_init = true; + if (__glibc_unlikely (audit_list != NULL) + || __glibc_unlikely (audit_list_string != NULL)) { - /* Iterate over all entries in the list. The order is important. */ struct audit_ifaces *last_audit = NULL; - struct audit_list *al = audit_list->next; + struct audit_list_iter al_iter; + audit_list_iter_init (&al_iter); /* Since we start using the auditing DSOs right away we need to initialize the data structures now. */ @@ -1272,9 +1417,14 @@ of this helper program; chances are you did not intend to run this program.\n\ use different values (especially the pointer guard) and will fail later on. */ security_init (); + need_security_init = false; - do + while (true) { + const char *name = audit_list_iter_next (&al_iter); + if (name == NULL) + break; + int tls_idx = GL(dl_tls_max_dtv_idx); /* Now it is time to determine the layout of the static TLS @@ -1283,7 +1433,7 @@ of this helper program; chances are you did not intend to run this program.\n\ no DF_STATIC_TLS bit is set. The reason is that we know glibc will use the static model. */ struct dlmopen_args dlmargs; - dlmargs.fname = al->name; + dlmargs.fname = name; dlmargs.map = NULL; const char *objname; @@ -1296,7 +1446,7 @@ of this helper program; chances are you did not intend to run this program.\n\ not_loaded: _dl_error_printf ("\ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", - al->name, err_str); + name, err_str); if (malloced) free ((char *) err_str); } @@ -1400,10 +1550,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", goto not_loaded; } } - - al = al->next; } - while (al != audit_list->next); /* If we have any auditing modules, announce that we already have two objects loaded. */ @@ -1481,23 +1628,8 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", if (__glibc_unlikely (preloadlist != NULL)) { - /* The LD_PRELOAD environment variable gives list of libraries - separated by white space or colons that are loaded before the - executable's dependencies and prepended to the global scope - list. If the binary is running setuid all elements - containing a '/' are ignored since it is insecure. */ - char *list = strdupa (preloadlist); - char *p; - HP_TIMING_NOW (start); - - /* Prevent optimizing strsep. Speed is not important here. */ - while ((p = (strsep) (&list, " :")) != NULL) - if (p[0] != '\0' - && (__builtin_expect (! __libc_enable_secure, 1) - || strchr (p, '/') == NULL)) - npreloads += do_preload (p, main_map, "LD_PRELOAD"); - + npreloads += handle_ld_preload (preloadlist, main_map); HP_TIMING_NOW (stop); HP_TIMING_DIFF (diff, start, stop); HP_TIMING_ACCUM_NT (load_time, diff); @@ -1682,7 +1814,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", if (tcbp == NULL) tcbp = init_tls (); - if (__glibc_likely (audit_list == NULL)) + if (__glibc_likely (need_security_init)) /* Initialize security features. But only if we have not done it earlier. */ security_init (); @@ -2313,9 +2445,7 @@ process_dl_audit (char *str) char *p; while ((p = (strsep) (&str, ":")) != NULL) - if (p[0] != '\0' - && (__builtin_expect (! __libc_enable_secure, 1) - || strchr (p, '/') == NULL)) + if (dso_name_valid_for_suid (p)) { /* This is using the local malloc, not the system malloc. The memory can never be freed. */ @@ -2379,7 +2509,7 @@ process_envvars (enum mode *modep) break; } if (memcmp (envline, "AUDIT", 5) == 0) - process_dl_audit (&envline[6]); + audit_list_string = &envline[6]; break; case 7: @@ -2423,7 +2553,8 @@ process_envvars (enum mode *modep) case 10: /* Mask for the important hardware capabilities. */ - if (memcmp (envline, "HWCAP_MASK", 10) == 0) + if (!__libc_enable_secure + && memcmp (envline, "HWCAP_MASK", 10) == 0) GLRO(dl_hwcap_mask) = __strtoul_internal (&envline[11], NULL, 0, 0); break; @@ -2437,7 +2568,8 @@ process_envvars (enum mode *modep) case 12: /* The library search path. */ - if (memcmp (envline, "LIBRARY_PATH", 12) == 0) + if (!__libc_enable_secure + && memcmp (envline, "LIBRARY_PATH", 12) == 0) { library_path = &envline[13]; break; diff --git a/elf/tst-nodelete-dlclose-dso.c b/elf/tst-nodelete-dlclose-dso.c new file mode 100644 index 0000000000..dd930f99cc --- /dev/null +++ b/elf/tst-nodelete-dlclose-dso.c @@ -0,0 +1,90 @@ +/* Bug 11941: Improper assert map->l_init_called in dlclose. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +/* This is the primary DSO that is loaded by the appliation. This DSO + then loads a plugin with RTLD_NODELETE. This plugin depends on this + DSO. This dependency chain means that at application shutdown the + plugin will be destructed first. Thus by the time this DSO is + destructed we will be calling dlclose on an object that has already + been destructed. It is allowed to call dlclose in this way and + should not assert. */ +#include +#include +#include + +/* Plugin to load. */ +static void *plugin_lib = NULL; +/* Plugin function. */ +static void (*plugin_func) (void); +#define LIB_PLUGIN "tst-nodelete-dlclose-plugin.so" + +/* This function is never called but the plugin references it. + We do this to avoid any future --as-needed from removing the + plugin's DT_NEEDED on this DSO (required for the test). */ +void +primary_reference (void) +{ + printf ("INFO: Called primary_reference function.\n"); +} + +void +primary (void) +{ + char *error; + + plugin_lib = dlopen (LIB_PLUGIN, RTLD_NOW | RTLD_LOCAL | RTLD_NODELETE); + if (plugin_lib == NULL) + { + printf ("ERROR: Unable to load plugin library.\n"); + exit (EXIT_FAILURE); + } + dlerror (); + + plugin_func = (void (*) (void)) dlsym (plugin_lib, "plugin_func"); + error = dlerror (); + if (error != NULL) + { + printf ("ERROR: Unable to find symbol with error \"%s\".", + error); + exit (EXIT_FAILURE); + } + + return; +} + +__attribute__ ((destructor)) +static void +primary_dtor (void) +{ + int ret; + + printf ("INFO: Calling primary destructor.\n"); + + /* The destructor runs in the test driver also, which + hasn't called primary, in that case do nothing. */ + if (plugin_lib == NULL) + return; + + ret = dlclose (plugin_lib); + if (ret != 0) + { + printf ("ERROR: Calling dlclose failed with \"%s\"\n", + dlerror ()); + exit (EXIT_FAILURE); + } +} diff --git a/elf/tst-nodelete-dlclose-plugin.c b/elf/tst-nodelete-dlclose-plugin.c new file mode 100644 index 0000000000..8b295c1718 --- /dev/null +++ b/elf/tst-nodelete-dlclose-plugin.c @@ -0,0 +1,40 @@ +/* Bug 11941: Improper assert map->l_init_called in dlclose. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +/* This DSO simulates a plugin with a dependency on the + primary DSO loaded by the appliation. */ +#include + +extern void primary_reference (void); + +void +plugin_func (void) +{ + printf ("INFO: Calling plugin function.\n"); + /* Need a reference to the DSO to ensure that a potential --as-needed + doesn't remove the DT_NEEDED entry which we rely upon to ensure + destruction ordering. */ + primary_reference (); +} + +__attribute__ ((destructor)) +static void +plugin_dtor (void) +{ + printf ("INFO: Calling plugin destructor.\n"); +} diff --git a/elf/tst-nodelete-dlclose.c b/elf/tst-nodelete-dlclose.c new file mode 100644 index 0000000000..b3d07e1849 --- /dev/null +++ b/elf/tst-nodelete-dlclose.c @@ -0,0 +1,36 @@ +/* Bug 11941: Improper assert map->l_init_called in dlclose. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +/* This simulates an application using the primary DSO which loads the + plugin DSO. */ +#include +#include + +extern void primary (void); + +static int +do_test (void) +{ + printf ("INFO: Starting application.\n"); + primary (); + printf ("INFO: Exiting application.\n"); + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/extra-lib.mk b/extra-lib.mk index b10748d185..2552049135 100644 --- a/extra-lib.mk +++ b/extra-lib.mk @@ -5,6 +5,9 @@ # The variable $($(lib)-routines) defines the list of modules # to be included in that library. A sysdep Makefile can add to # $(lib)-sysdep_routines to include additional modules. +# +# Libraries listed in $(extra-libs-noinstall) are built, but not +# installed. lib := $(firstword $(extra-libs-left)) extra-libs-left := $(filter-out $(lib),$(extra-libs-left)) @@ -28,7 +31,9 @@ extra-objs := $(extra-objs) all-$(lib)-routines := $($(lib)-routines) $($(lib)-sysdep_routines) # Add each flavor of library to the lists of things to build and install. +ifeq (,$(filter $(lib), $(extra-libs-noinstall))) install-lib += $(foreach o,$(object-suffixes-$(lib)),$(lib:lib%=$(libtype$o))) +endif extra-objs += $(foreach o,$(filter-out .os .oS,$(object-suffixes-$(lib))),\ $(patsubst %,%$o,$(filter-out \ $($(lib)-shared-only-routines),\ diff --git a/grp/grp-merge.c b/grp/grp-merge.c index 0a1eb38d2c..5f79755798 100644 --- a/grp/grp-merge.c +++ b/grp/grp-merge.c @@ -85,6 +85,14 @@ __copy_grp (const struct group srcgrp, const size_t buflen, } members[i] = NULL; + /* Align for pointers. We can't simply align C because we need to + align destbuf[c]. */ + if ((((uintptr_t)destbuf + c) & (__alignof__(char **) - 1)) != 0) + { + uintptr_t mis_align = ((uintptr_t)destbuf + c) & (__alignof__(char **) - 1); + c += __alignof__(char **) - mis_align; + } + /* Copy the pointers from the members array into the buffer and assign them to the gr_mem member of destgrp. */ destgrp->gr_mem = (char **) &destbuf[c]; @@ -129,7 +137,7 @@ __merge_grp (struct group *savedgrp, char *savedbuf, char *savedend, /* Get the count of group members from the last sizeof (size_t) bytes in the mergegrp buffer. */ - savedmemcount = (size_t) *(savedend - sizeof (size_t)); + savedmemcount = *(size_t *) (savedend - sizeof (size_t)); /* Get the count of new members to add. */ for (memcount = 0; mergegrp->gr_mem[memcount]; memcount++) @@ -168,6 +176,14 @@ __merge_grp (struct group *savedgrp, char *savedbuf, char *savedend, /* Add the NULL-terminator. */ members[savedmemcount + memcount] = NULL; + /* Align for pointers. We can't simply align C because we need to + align savedbuf[c]. */ + if ((((uintptr_t)savedbuf + c) & (__alignof__(char **) - 1)) != 0) + { + uintptr_t mis_align = ((uintptr_t)savedbuf + c) & (__alignof__(char **) - 1); + c += __alignof__(char **) - mis_align; + } + /* Copy the member array back into the buffer after the member list and free the member array. */ savedgrp->gr_mem = (char **) &savedbuf[c]; diff --git a/iconv/gconv.h b/iconv/gconv.h index 8d8ce5813b..a87028047b 100644 --- a/iconv/gconv.h +++ b/iconv/gconv.h @@ -139,7 +139,7 @@ typedef struct __gconv_info { size_t __nsteps; struct __gconv_step *__steps; - __extension__ struct __gconv_step_data __data __flexarr; + __extension__ struct __gconv_step_data __data[0]; } *__gconv_t; /* Transliteration using the locale's data. */ diff --git a/include/arpa/nameser_compat.h b/include/arpa/nameser_compat.h index 2e735ede4c..7c0deed9ae 100644 --- a/include/arpa/nameser_compat.h +++ b/include/arpa/nameser_compat.h @@ -1,8 +1,8 @@ #ifndef _ARPA_NAMESER_COMPAT_ #include -/* Picksome unused number to represent lookups of IPv4 and IPv6 (i.e., - T_A and T_AAAA). */ -#define T_UNSPEC 62321 +/* The number is outside the 16-bit RR type range and is used + internally by the implementation. */ +#define T_QUERY_A_AND_AAAA 439963904 #endif diff --git a/include/array_length.h b/include/array_length.h new file mode 100644 index 0000000000..cb4a8b2a56 --- /dev/null +++ b/include/array_length.h @@ -0,0 +1,36 @@ +/* The array_length and array_end macros. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef _ARRAY_LENGTH_H +#define _ARRAY_LENGTH_H + +/* array_length (VAR) is the number of elements in the array VAR. VAR + must evaluate to an array, not a pointer. */ +#define array_length(var) \ + __extension__ ({ \ + _Static_assert (!__builtin_types_compatible_p \ + (__typeof (var), __typeof (&(var)[0])), \ + "argument must be an array"); \ + sizeof (var) / sizeof ((var)[0]); \ + }) + +/* array_end (VAR) is a pointer one past the end of the array VAR. + VAR must evaluate to an array, not a pointer. */ +#define array_end(var) (&(var)[array_length (var)]) + +#endif /* _ARRAY_LENGTH_H */ diff --git a/io/Makefile b/io/Makefile index deb6100156..1128f4881f 100644 --- a/io/Makefile +++ b/io/Makefile @@ -71,7 +71,8 @@ tests := test-utime test-stat test-stat2 test-lfs tst-getcwd \ tst-renameat tst-fchownat tst-fchmodat tst-faccessat \ tst-symlinkat tst-linkat tst-readlinkat tst-mkdirat \ tst-mknodat tst-mkfifoat tst-ttyname_r bug-ftw5 \ - tst-posix_fallocate tst-fts tst-fts-lfs + tst-posix_fallocate tst-posix_fallocate64 \ + tst-fts tst-fts-lfs tst-open-tmpfile tst-getcwd-abspath ifeq ($(run-built-tests),yes) tests-special += $(objpfx)ftwtest.out diff --git a/io/fts.h b/io/fts.h index 127a0d2721..b6b45206c8 100644 --- a/io/fts.h +++ b/io/fts.h @@ -193,7 +193,7 @@ FTS *__REDIRECT (fts_open, (char * const *, int, int (*)(const FTSENT **, const FTSENT **)), fts64_open); FTSENT *__REDIRECT (fts_read, (FTS *), fts64_read); -int __REDIRECT (fts_set, (FTS *, FTSENT *, int), fts64_set) __THROW; +int __REDIRECT_NTH (fts_set, (FTS *, FTSENT *, int), fts64_set); # else # define fts_children fts64_children # define fts_close fts64_close diff --git a/io/tst-getcwd-abspath.c b/io/tst-getcwd-abspath.c new file mode 100644 index 0000000000..3a3636f2ed --- /dev/null +++ b/io/tst-getcwd-abspath.c @@ -0,0 +1,66 @@ +/* BZ #22679 getcwd(3) should not succeed without returning an absolute path. + + Copyright (C) 2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static char *chroot_dir; + +/* The actual test. Run it in a subprocess, so that the test harness + can remove the temporary directory in --direct mode. */ +static void +getcwd_callback (void *closure) +{ + xchroot (chroot_dir); + + errno = 0; + char *cwd = getcwd (NULL, 0); + TEST_COMPARE (errno, ENOENT); + TEST_VERIFY (cwd == NULL); + + errno = 0; + cwd = realpath (".", NULL); + TEST_COMPARE (errno, ENOENT); + TEST_VERIFY (cwd == NULL); + + _exit (0); +} + +static int +do_test (void) +{ + support_become_root (); + if (!support_can_chroot ()) + return EXIT_UNSUPPORTED; + + chroot_dir = support_create_temp_directory ("tst-getcwd-abspath-"); + support_isolate_in_subprocess (getcwd_callback, NULL); + + return 0; +} + +#include diff --git a/localedata/ChangeLog b/localedata/ChangeLog index 4be8afc110..a7688e3df6 100644 --- a/localedata/ChangeLog +++ b/localedata/ChangeLog @@ -1,3 +1,17 @@ +2017-06-11 Santhosh Thottingal + + [BZ #19922] + * locales/iso14651_t1_common: Add collation rules for U+07DA to U+07DF. + + [BZ #19919] + * locales/iso14651_t1_common: Correct collation of U+0D36 and U+0D37. + +2016-12-30 Mike Frysinger + + [BZ #20974] + * localedata/bs_BA (LC_MESSAGES): Delete "*." from the end of + yesexpr and noexpr. + 2016-07-07 Aurelien Jarno * locales/de_LI (postal_fmt): Fix indentation. diff --git a/localedata/locales/bs_BA b/localedata/locales/bs_BA index a47f87eb37..68c2f9471a 100644 --- a/localedata/locales/bs_BA +++ b/localedata/locales/bs_BA @@ -148,8 +148,8 @@ copy "en_DK" END LC_CTYPE LC_MESSAGES -yesexpr "" -noexpr "" +yesexpr "" +noexpr "" yesstr "" nostr "" END LC_MESSAGES diff --git a/localedata/locales/iso14651_t1_common b/localedata/locales/iso14651_t1_common index eef75ba65e..0e64f26a12 100644 --- a/localedata/locales/iso14651_t1_common +++ b/localedata/locales/iso14651_t1_common @@ -1042,9 +1042,9 @@ collating-element from "" collating-element from "" collating-element from "" collating-element from "" -collating-element from "" collating-element from "" collating-element from "" +collating-element from "" collating-element from "" collating-element from "" collating-element from "" @@ -1103,8 +1103,8 @@ collating-symbol collating-symbol collating-symbol collating-symbol -collating-symbol collating-symbol +collating-symbol collating-symbol collating-symbol collating-symbol @@ -1126,6 +1126,12 @@ collating-symbol collating-symbol collating-symbol collating-symbol +collating-symbol +collating-symbol +collating-symbol +collating-symbol +collating-symbol +collating-symbol # # # @@ -4552,6 +4558,12 @@ collating-symbol + + + + + + # # # @@ -7252,6 +7264,7 @@ order_start ;forward;forward;forward;forward,position ;;;IGNORE ;;;IGNORE "";;;IGNORE + "";;;IGNORE "";;;IGNORE "";;;IGNORE "";;;IGNORE @@ -7280,6 +7293,7 @@ order_start ;forward;forward;forward;forward,position "";;;IGNORE "";;;IGNORE "";;;IGNORE # ണ്‍ = ണ + ് + zwj + "";;;IGNORE "";;;IGNORE # ണ = ണ + ് + അ "";;;IGNORE "";;;IGNORE @@ -7290,6 +7304,7 @@ order_start ;forward;forward;forward;forward,position "";;;IGNORE "";;;IGNORE "";;;IGNORE # ന്‍= ന + ് + zwj + "";;;IGNORE "";;;IGNORE #ന = ന + ് + അ "";;;IGNORE "";;;IGNORE @@ -7305,20 +7320,23 @@ order_start ;forward;forward;forward;forward,position "";;;IGNORE "";;;IGNORE "";;;IGNORE # ര = ര + ് + zwj + "";;;IGNORE "";;;IGNORE # ര = ര + ് + അ ;;;IGNORE # ല്‍ = ല + ് + zwj + "";;;IGNORE "";;;IGNORE # ല = ല + ് + അ "";;;IGNORE "";;;IGNORE "";;;IGNORE - "";;;IGNORE + "";;;IGNORE "";;;IGNORE - "";;;IGNORE + "";;;IGNORE "";;;IGNORE "";;;IGNORE "";;;IGNORE "";;;IGNORE "";;;IGNORE # ള്‍ = ള + ് + zwj + "";;;IGNORE "";;;IGNORE # ള = ള + ് + അ "";;;IGNORE "";;;IGNORE diff --git a/malloc/arena.c b/malloc/arena.c index 229783f3b7..4e16593d8b 100644 --- a/malloc/arena.c +++ b/malloc/arena.c @@ -702,8 +702,7 @@ _int_new_arena (size_t size) } -/* Remove an arena from free_list. The arena may be in use because it - was attached concurrently to a thread by reused_arena below. */ +/* Remove an arena from free_list. */ static mstate get_free_list (void) { @@ -718,7 +717,8 @@ get_free_list (void) free_list = result->next_free; /* The arena will be attached to this thread. */ - ++result->attached_threads; + assert (result->attached_threads == 0); + result->attached_threads = 1; detach_arena (replaced_arena); } @@ -735,6 +735,26 @@ get_free_list (void) return result; } +/* Remove the arena from the free list (if it is present). + free_list_lock must have been acquired by the caller. */ +static void +remove_from_free_list (mstate arena) +{ + mstate *previous = &free_list; + for (mstate p = free_list; p != NULL; p = p->next_free) + { + assert (p->attached_threads == 0); + if (p == arena) + { + /* Remove the requested arena from the list. */ + *previous = p->next_free; + break; + } + else + previous = &p->next_free; + } +} + /* Lock and return an arena that can be reused for memory allocation. Avoid AVOID_ARENA as we have already failed to allocate memory in it and it is currently locked. */ @@ -782,14 +802,25 @@ reused_arena (mstate avoid_arena) (void) mutex_lock (&result->mutex); out: - /* Attach the arena to the current thread. Note that we may have - selected an arena which was on free_list. */ + /* Attach the arena to the current thread. */ { /* Update the arena thread attachment counters. */ mstate replaced_arena = thread_arena; (void) mutex_lock (&free_list_lock); detach_arena (replaced_arena); + + /* We may have picked up an arena on the free list. We need to + preserve the invariant that no arena on the free list has a + positive attached_threads counter (otherwise, + arena_thread_freeres cannot use the counter to determine if the + arena needs to be put on the free list). We unconditionally + remove the selected arena from the free list. The caller of + reused_arena checked the free list and observed it to be empty, + so the list is very short. */ + remove_from_free_list (result); + ++result->attached_threads; + (void) mutex_unlock (&free_list_lock); } diff --git a/misc/regexp.c b/misc/regexp.c index 3b3668272f..b2a2c6e636 100644 --- a/misc/regexp.c +++ b/misc/regexp.c @@ -29,14 +29,15 @@ #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_23) -/* Define the variables used for the interface. */ -char *loc1; -char *loc2; +/* Define the variables used for the interface. Avoid .symver on common + symbol, which just creates a new common symbol, not an alias. */ +char *loc1 __attribute__ ((nocommon)); +char *loc2 __attribute__ ((nocommon)); compat_symbol (libc, loc1, loc1, GLIBC_2_0); compat_symbol (libc, loc2, loc2, GLIBC_2_0); /* Although we do not support the use we define this variable as well. */ -char *locs; +char *locs __attribute__ ((nocommon)); compat_symbol (libc, locs, locs, GLIBC_2_0); diff --git a/nis/nss_nisplus/nisplus-alias.c b/nis/nss_nisplus/nisplus-alias.c index 7f698b4e6d..cb5acce01d 100644 --- a/nis/nss_nisplus/nisplus-alias.c +++ b/nis/nss_nisplus/nisplus-alias.c @@ -291,7 +291,7 @@ _nss_nisplus_getaliasbyname_r (const char *name, struct aliasent *alias, return status; } - if (name != NULL) + if (name == NULL) { *errnop = EINVAL; return NSS_STATUS_UNAVAIL; diff --git a/nptl/Makefile b/nptl/Makefile index 0d8aadebed..fa925819ca 100644 --- a/nptl/Makefile +++ b/nptl/Makefile @@ -268,7 +268,7 @@ tests = tst-typesizes \ tst-flock1 tst-flock2 \ tst-signal1 tst-signal2 tst-signal3 tst-signal4 tst-signal5 \ tst-signal6 tst-signal7 \ - tst-exec1 tst-exec2 tst-exec3 tst-exec4 \ + tst-exec1 tst-exec2 tst-exec3 tst-exec4 tst-exec5 \ tst-exit1 tst-exit2 tst-exit3 \ tst-stdio1 tst-stdio2 \ tst-stack1 tst-stack2 tst-stack3 tst-stack4 tst-pthread-getattr \ diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c index 6b42b11d5a..7365ca606b 100644 --- a/nptl/allocatestack.c +++ b/nptl/allocatestack.c @@ -440,9 +440,6 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp, SETUP_THREAD_SYSINFO (pd); #endif - /* The process ID is also the same as that of the caller. */ - pd->pid = THREAD_GETMEM (THREAD_SELF, pid); - /* Don't allow setxid until cloned. */ pd->setxid_futex = -1; @@ -579,9 +576,6 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp, /* Don't allow setxid until cloned. */ pd->setxid_futex = -1; - /* The process ID is also the same as that of the caller. */ - pd->pid = THREAD_GETMEM (THREAD_SELF, pid); - /* Allocate the DTV for this thread. */ if (_dl_allocate_tls (TLS_TPADJ (pd)) == NULL) { @@ -875,9 +869,6 @@ __reclaim_stacks (void) /* This marks the stack as free. */ curp->tid = 0; - /* The PID field must be initialized for the new process. */ - curp->pid = self->pid; - /* Account for the size of the stack. */ stack_cache_actsize += curp->stackblock_size; @@ -903,13 +894,6 @@ __reclaim_stacks (void) } } - /* Reset the PIDs in any cached stacks. */ - list_for_each (runp, &stack_cache) - { - struct pthread *curp = list_entry (runp, struct pthread, list); - curp->pid = self->pid; - } - /* Add the stack of all running threads to the cache. */ list_splice (&stack_used, &stack_cache); @@ -1054,9 +1038,9 @@ setxid_signal_thread (struct xid_command *cmdp, struct pthread *t) return 0; int val; + pid_t pid = __getpid (); INTERNAL_SYSCALL_DECL (err); - val = INTERNAL_SYSCALL (tgkill, err, 3, THREAD_GETMEM (THREAD_SELF, pid), - t->tid, SIGSETXID); + val = INTERNAL_SYSCALL_CALL (tgkill, err, pid, t->tid, SIGSETXID); /* If this failed, it must have had not started yet or else exited. */ if (!INTERNAL_SYSCALL_ERROR_P (val, err)) diff --git a/nptl/descr.h b/nptl/descr.h index 8e4938deb5..bc92abf010 100644 --- a/nptl/descr.h +++ b/nptl/descr.h @@ -167,8 +167,8 @@ struct pthread therefore stack) used' flag. */ pid_t tid; - /* Process ID - thread group ID in kernel speak. */ - pid_t pid; + /* Ununsed. */ + pid_t pid_ununsed; /* List of robust mutexes the thread is holding. */ #ifdef __PTHREAD_MUTEX_HAVE_PREV diff --git a/nptl/nptl-init.c b/nptl/nptl-init.c index bdbdfedcef..48fab50c4e 100644 --- a/nptl/nptl-init.c +++ b/nptl/nptl-init.c @@ -184,18 +184,12 @@ __nptl_set_robust (struct pthread *self) static void sigcancel_handler (int sig, siginfo_t *si, void *ctx) { - /* Determine the process ID. It might be negative if the thread is - in the middle of a fork() call. */ - pid_t pid = THREAD_GETMEM (THREAD_SELF, pid); - if (__glibc_unlikely (pid < 0)) - pid = -pid; - /* Safety check. It would be possible to call this function for other signals and send a signal from another process. This is not correct and might even be a security problem. Try to catch as many incorrect invocations as possible. */ if (sig != SIGCANCEL - || si->si_pid != pid + || si->si_pid != __getpid() || si->si_code != SI_TKILL) return; @@ -243,19 +237,14 @@ struct xid_command *__xidcmd attribute_hidden; static void sighandler_setxid (int sig, siginfo_t *si, void *ctx) { - /* Determine the process ID. It might be negative if the thread is - in the middle of a fork() call. */ - pid_t pid = THREAD_GETMEM (THREAD_SELF, pid); int result; - if (__glibc_unlikely (pid < 0)) - pid = -pid; /* Safety check. It would be possible to call this function for other signals and send a signal from another process. This is not correct and might even be a security problem. Try to catch as many incorrect invocations as possible. */ if (sig != SIGSETXID - || si->si_pid != pid + || si->si_pid != __getpid () || si->si_code != SI_TKILL) return; diff --git a/nptl/pthread_cancel.c b/nptl/pthread_cancel.c index 1419baf988..89d02e1741 100644 --- a/nptl/pthread_cancel.c +++ b/nptl/pthread_cancel.c @@ -22,7 +22,7 @@ #include "pthreadP.h" #include #include - +#include int pthread_cancel (pthread_t th) @@ -66,19 +66,11 @@ pthread_cancel (pthread_t th) #ifdef SIGCANCEL /* The cancellation handler will take care of marking the thread as canceled. */ - INTERNAL_SYSCALL_DECL (err); - - /* One comment: The PID field in the TCB can temporarily be - changed (in fork). But this must not affect this code - here. Since this function would have to be called while - the thread is executing fork, it would have to happen in - a signal handler. But this is no allowed, pthread_cancel - is not guaranteed to be async-safe. */ - int val; - val = INTERNAL_SYSCALL (tgkill, err, 3, - THREAD_GETMEM (THREAD_SELF, pid), pd->tid, - SIGCANCEL); + pid_t pid = getpid (); + INTERNAL_SYSCALL_DECL (err); + int val = INTERNAL_SYSCALL_CALL (tgkill, err, pid, pd->tid, + SIGCANCEL); if (INTERNAL_SYSCALL_ERROR_P (val, err)) result = INTERNAL_SYSCALL_ERRNO (val, err); #else diff --git a/nptl/pthread_getattr_np.c b/nptl/pthread_getattr_np.c index fb906f0484..32d7484bf8 100644 --- a/nptl/pthread_getattr_np.c +++ b/nptl/pthread_getattr_np.c @@ -68,7 +68,6 @@ pthread_getattr_np (pthread_t thread_id, pthread_attr_t *attr) { /* No stack information available. This must be for the initial thread. Get the info in some magical way. */ - assert (abs (thread->pid) == thread->tid); /* Stack size limit. */ struct rlimit rl; diff --git a/nptl/tst-exec5.c b/nptl/tst-exec5.c new file mode 100644 index 0000000000..4327d8d41c --- /dev/null +++ b/nptl/tst-exec5.c @@ -0,0 +1,196 @@ +/* Check if posix_spawn does not act as a cancellation entrypoint. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int do_test (void); +#define TEST_FUNCTION do_test () +#include + +static pthread_barrier_t b; + +static pid_t pid; +static int pipefd[2]; + +static void * +tf (void *arg) +{ + int r = pthread_barrier_wait (&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("error: pthread_barrier_wait failed"); + exit (1); + } + + posix_spawn_file_actions_t a; + if (posix_spawn_file_actions_init (&a) != 0) + { + puts ("error: spawn_file_actions_init failed"); + exit (1); + } + + if (posix_spawn_file_actions_adddup2 (&a, pipefd[1], STDOUT_FILENO) != 0) + { + puts ("error: spawn_file_actions_adddup2 failed"); + exit (1); + } + + if (posix_spawn_file_actions_addclose (&a, pipefd[0]) != 0) + { + puts ("error: spawn_file_actions_addclose"); + exit (1); + } + + char *argv[] = { (char *) _PATH_BSHELL, (char *) "-c", (char *) "echo $$", + NULL }; + if (posix_spawn (&pid, _PATH_BSHELL, &a, NULL, argv, NULL) != 0) + { + puts ("error: spawn failed"); + exit (1); + } + + return NULL; +} + + +static int +do_test (void) +{ + /* The test basically pipe a 'echo $$' created by a thread with a + cancellation pending. It then checks if the thread is not cancelled, + the process is created and if the output is the expected one. */ + + if (pipe (pipefd) != 0) + { + puts ("error: pipe failed"); + exit (1); + } + + /* Not interested in knowing when the pipe is closed. */ + if (sigignore (SIGPIPE) != 0) + { + puts ("error: sigignore failed"); + exit (1); + } + + /* To synchronize with the thread. */ + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("error: pthread_barrier_init failed"); + exit (1); + } + + pthread_t th; + if (pthread_create (&th, NULL, &tf, NULL) != 0) + { + puts ("error: pthread_create failed"); + exit (1); + } + + if (pthread_cancel (th) != 0) + { + puts ("error: pthread_cancel failed"); + exit (1); + } + + int r = pthread_barrier_wait (&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("error: pthread_barrier_wait"); + exit (1); + } + + void *retval; + if (pthread_join (th, &retval) != 0) + { + puts ("error: pthread_join failed\n"); + } + if (retval == PTHREAD_CANCELED) + { + puts ("error: thread cancelled"); + exit (1); + } + + close (pipefd[1]); + + /* The global 'pid' should be set by thread posix_spawn calling. Check + below if it was executed correctly and with expected output. */ + + char buf[64]; + ssize_t n; + bool seen_pid = false; + while (TEMP_FAILURE_RETRY ((n = read (pipefd[0], buf, sizeof (buf)))) > 0) + { + /* We only expect to read the PID. */ + char *endp; + long int rpid = strtol (buf, &endp, 10); + + if (*endp != '\n') + { + printf ("error: didn't parse whole line: \"%s\"\n", buf); + exit (1); + } + if (endp == buf) + { + puts ("error: read empty line"); + exit (1); + } + + if (rpid != pid) + { + printf ("error: found \"%s\", expected PID %ld\n", buf, + (long int) pid); + exit (1); + } + + if (seen_pid) + { + puts ("error: found more than one PID line"); + exit (1); + } + + seen_pid = true; + } + + close (pipefd[0]); + + int status; + int err = waitpid (pid, &status, 0); + if (err != pid) + { + puts ("errnor: waitpid failed"); + exit (1); + } + + if (!seen_pid) + { + puts ("error: didn't get PID"); + exit (1); + } + + return 0; +} diff --git a/nptl/tst-once5.cc b/nptl/tst-once5.cc index 978d8271bd..513ac53f6f 100644 --- a/nptl/tst-once5.cc +++ b/nptl/tst-once5.cc @@ -75,5 +75,7 @@ do_test (void) return result; } +// The test currently hangs and is XFAILed. Reduce the timeout. +#define TIMEOUT 1 #define TEST_FUNCTION do_test () #include "../test-skeleton.c" diff --git a/nptl_db/structs.def b/nptl_db/structs.def index a9b621b126..1cb6a46391 100644 --- a/nptl_db/structs.def +++ b/nptl_db/structs.def @@ -48,7 +48,6 @@ DB_STRUCT (pthread) DB_STRUCT_FIELD (pthread, list) DB_STRUCT_FIELD (pthread, report_events) DB_STRUCT_FIELD (pthread, tid) -DB_STRUCT_FIELD (pthread, pid) DB_STRUCT_FIELD (pthread, start_routine) DB_STRUCT_FIELD (pthread, cancelhandling) DB_STRUCT_FIELD (pthread, schedpolicy) diff --git a/nptl_db/td_ta_thr_iter.c b/nptl_db/td_ta_thr_iter.c index a990fed150..9e5059956b 100644 --- a/nptl_db/td_ta_thr_iter.c +++ b/nptl_db/td_ta_thr_iter.c @@ -76,48 +76,28 @@ iterate_thread_list (td_thragent_t *ta, td_thr_iter_f *callback, if (ps_pdread (ta->ph, addr, copy, ta->ta_sizeof_pthread) != PS_OK) return TD_ERR; - /* Verify that this thread's pid field matches the child PID. - If its pid field is negative, it's about to do a fork or it - is the sole thread in a fork child. */ - psaddr_t pid; - err = DB_GET_FIELD_LOCAL (pid, ta, copy, pthread, pid, 0); - if (err == TD_OK && (pid_t) (uintptr_t) pid < 0) - { - if (-(pid_t) (uintptr_t) pid == match_pid) - /* It is about to do a fork, but is really still the parent PID. */ - pid = (psaddr_t) (uintptr_t) match_pid; - else - /* It must be a fork child, whose new PID is in the tid field. */ - err = DB_GET_FIELD_LOCAL (pid, ta, copy, pthread, tid, 0); - } + err = DB_GET_FIELD_LOCAL (schedpolicy, ta, copy, pthread, + schedpolicy, 0); if (err != TD_OK) break; + err = DB_GET_FIELD_LOCAL (schedprio, ta, copy, pthread, + schedparam_sched_priority, 0); + if (err != TD_OK) + break; + + /* Now test whether this thread matches the specified conditions. */ - if ((pid_t) (uintptr_t) pid == match_pid) + /* Only if the priority level is as high or higher. */ + int descr_pri = ((uintptr_t) schedpolicy == SCHED_OTHER + ? 0 : (uintptr_t) schedprio); + if (descr_pri >= ti_pri) { - err = DB_GET_FIELD_LOCAL (schedpolicy, ta, copy, pthread, - schedpolicy, 0); - if (err != TD_OK) - break; - err = DB_GET_FIELD_LOCAL (schedprio, ta, copy, pthread, - schedparam_sched_priority, 0); - if (err != TD_OK) - break; - - /* Now test whether this thread matches the specified conditions. */ - - /* Only if the priority level is as high or higher. */ - int descr_pri = ((uintptr_t) schedpolicy == SCHED_OTHER - ? 0 : (uintptr_t) schedprio); - if (descr_pri >= ti_pri) - { - /* Yep, it matches. Call the callback function. */ - td_thrhandle_t th; - th.th_ta_p = (td_thragent_t *) ta; - th.th_unique = addr; - if (callback (&th, cbdata_p) != 0) - return TD_DBERR; - } + /* Yep, it matches. Call the callback function. */ + td_thrhandle_t th; + th.th_ta_p = (td_thragent_t *) ta; + th.th_unique = addr; + if (callback (&th, cbdata_p) != 0) + return TD_DBERR; } /* Get the pointer to the next element. */ diff --git a/nptl_db/td_thr_validate.c b/nptl_db/td_thr_validate.c index f3c8a7bed6..9b89fecad2 100644 --- a/nptl_db/td_thr_validate.c +++ b/nptl_db/td_thr_validate.c @@ -80,28 +80,5 @@ td_thr_validate (const td_thrhandle_t *th) err = TD_OK; } - if (err == TD_OK) - { - /* Verify that this is not a stale element in a fork child. */ - pid_t match_pid = ps_getpid (th->th_ta_p->ph); - psaddr_t pid; - err = DB_GET_FIELD (pid, th->th_ta_p, th->th_unique, pthread, pid, 0); - if (err == TD_OK && (pid_t) (uintptr_t) pid < 0) - { - /* This was a thread that was about to fork, or it is the new sole - thread in a fork child. In the latter case, its tid was stored - via CLONE_CHILD_SETTID and so is already the proper child PID. */ - if (-(pid_t) (uintptr_t) pid == match_pid) - /* It is about to do a fork, but is really still the parent PID. */ - pid = (psaddr_t) (uintptr_t) match_pid; - else - /* It must be a fork child, whose new PID is in the tid field. */ - err = DB_GET_FIELD (pid, th->th_ta_p, th->th_unique, - pthread, tid, 0); - } - if (err == TD_OK && (pid_t) (uintptr_t) pid != match_pid) - err = TD_NOTHR; - } - return err; } diff --git a/po/de.po b/po/de.po index 1383e8c4a9..ca14c7e386 100644 --- a/po/de.po +++ b/po/de.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: GNU libc 2.22-pre1\n" "POT-Creation-Date: 2015-07-31 00:10-0400\n" -"PO-Revision-Date: 2015-08-31 18:30+0200\n" +"PO-Revision-Date: 2016-04-22 18:44+0200\n" "Last-Translator: Jochen Hein \n" "Language-Team: German \n" "Language: de\n" @@ -4479,13 +4479,13 @@ msgstr "" "%15s Cache ist dauerhaft\n" "%15s Cache wird gemeinsam verwendet\n" "%15Zu vorgeschlagene Größe\n" -"%15Zu Gesamtröße des Data-Pools\n" +"%15Zu Gesamtgröße des Data-Pools\n" "%15Zu Benutzter Speicher im Data-Pool\n" "%15lu Time to Live für positive Einträge in Sekunden\n" "%15lu Time to Live für negative Einträge in Sekunden\n" "%15 Cache-Hits bei positiven Einträgen\n" "%15 Cache-Hits bei positiven Einträgen\n" -"%15 Cache-Misses bei positiven Einträgen\n" +"%15 Cache-Misses bei positiven Einträgen\n" "%15 Cache-Misses bei negativen Einträgen\n" "%15lu%% Cache-Hit Verhältnis\n" "%15zu aktuelle Anzahl der Werte im Cache\n" diff --git a/po/fi.po b/po/fi.po index 17cb3e3e1d..8a2ab8358c 100644 --- a/po/fi.po +++ b/po/fi.po @@ -24,16 +24,16 @@ # msgid "" msgstr "" -"Project-Id-Version: libc 2.21-pre1\n" +"Project-Id-Version: libc 2.22-pre1\n" "POT-Creation-Date: 2015-07-31 00:10-0400\n" -"PO-Revision-Date: 2015-07-28 20:29+0300\n" +"PO-Revision-Date: 2016-05-26 21:14+0300\n" "Last-Translator: Lauri Nurmi \n" "Language-Team: Finnish \n" "Language: fi\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 1.8.3\n" +"X-Generator: Poedit 1.8.7\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: argp/argp-help.c:227 @@ -126,7 +126,7 @@ msgid "%s%s%s:%u: %s%sUnexpected error: %s.\n" msgstr "%s%s%s:%u: %s%sOdottamaton virhe: %s.\n" #: assert/assert.c:101 -#, fuzzy, c-format +#, c-format msgid "" "%s%s%s:%u: %s%sAssertion `%s' failed.\n" "%n" @@ -169,12 +169,12 @@ msgstr "" #: malloc/memusagestat.c:563 nss/getent.c:973 nss/makedb.c:369 #: posix/getconf.c:486 sunrpc/rpcinfo.c:691 #: sysdeps/unix/sysv/linux/lddlibc4.c:61 -#, fuzzy, c-format +#, c-format msgid "" "For bug reporting instructions, please see:\n" "%s.\n" msgstr "" -"Ohjeet ohjelmistovioista ilmoittamiseen ovat osoitteessa\n" +"Katso ohjeet vikailmoitusten tekemiseen osoitteesta:\n" "%s.\n" #: catgets/gencat.c:245 debug/pcprofiledump.c:225 debug/xtrace.sh:64 @@ -321,9 +321,8 @@ msgstr "Käyttö: xtrace [VALITSIN]... OHJELMA [OHJELMANVALITSIN]...\\n" #: debug/xtrace.sh:32 elf/sotruss.sh:56 elf/sotruss.sh:67 elf/sotruss.sh:135 #: malloc/memusage.sh:26 -#, fuzzy msgid "Try \\`%s --help' or \\`%s --usage' for more information.\\n" -msgstr "Kokeile ”%s --help” tai ”%s --usage” saadaksesi lisää tietoa.\n" +msgstr "Kokeile ”%s --help” tai ”%s --usage” saadaksesi lisää tietoa.\\n" #: debug/xtrace.sh:38 #, fuzzy @@ -594,9 +593,8 @@ msgid "cannot enable executable stack as shared object requires" msgstr "jaettua objektikahvaa ei voi luoda" #: elf/dl-load.c:1339 -#, fuzzy msgid "cannot close file descriptor" -msgstr "tiedostoa %s ei voi sulkea" +msgstr "tiedostokahvaa ei voi sulkea" #: elf/dl-load.c:1568 msgid "file too short" @@ -796,9 +794,8 @@ msgid "Format to use: new, old or compat (default)" msgstr "Käytettävä muoto: ”new”, ”old” tai ”compat” (oletus)" #: elf/ldconfig.c:151 -#, fuzzy msgid "Ignore auxiliary cache file" -msgstr "Käytä CACHEa välimuistitiedostona" +msgstr "Jätä huomiotta apuvälimuistitiedosto" #: elf/ldconfig.c:159 msgid "Configure Dynamic Linker Run Time Bindings." @@ -1087,9 +1084,9 @@ msgid "invalid process ID '%s'" msgstr "virheellinen prosessi-ID ”%s”" #: elf/pldd.c:120 -#, fuzzy, c-format +#, c-format msgid "cannot open %s" -msgstr "laitetta %s ei voi avata" +msgstr "tiedostoa %s ei voi avata" #: elf/pldd.c:152 #, fuzzy, c-format @@ -1102,24 +1099,24 @@ msgid "cannot prepare reading %s/task" msgstr "ei voi avata laitetta %s lukutilaan" #: elf/pldd.c:168 -#, fuzzy, c-format +#, c-format msgid "invalid thread ID '%s'" -msgstr "virheellinen prosessi-ID ”%s”" +msgstr "virheellinen säie-ID ”%s”" #: elf/pldd.c:179 -#, fuzzy, c-format +#, c-format msgid "cannot attach to process %lu" -msgstr "tiedostoa ”%s” ei voi avata" +msgstr "ei voida kiinnittyä prosessiin %lu" #: elf/pldd.c:294 #, c-format msgid "cannot get information about process %lu" -msgstr "" +msgstr "tietojen saaminen prosessista %lu ei onnistu" #: elf/pldd.c:307 -#, fuzzy, c-format +#, c-format msgid "process %lu is no ELF program" -msgstr "ohjelma %lu ei ole käytettävissä\n" +msgstr "prosessi %lu ei ole ELF-ohjelma" #: elf/readelflib.c:34 #, c-format @@ -1203,7 +1200,7 @@ msgstr "%s kohde ei saa olla hakemisto\n" #: elf/sln.c:184 #, c-format msgid "%s: failed to remove the old destination\n" -msgstr "" +msgstr "%s: vanhan kohteen poistaminen epäonnistui\n" #: elf/sln.c:192 #, c-format @@ -1237,9 +1234,8 @@ msgid "Mandatory arguments to long options are also mandatory for any correspond msgstr "Pakolliset argumentit pitkille valitsimille ovat pakollisia kaikille vastaaville lyhyille valitsimille.\\n" #: elf/sotruss.sh:55 -#, fuzzy msgid "%s: option requires an argument -- '%s'\\n" -msgstr "%s: valitsin ”%s” vaatii argumentin\n" +msgstr "%s: valitsin vaatii argumentin -- ”%c”\\n" #: elf/sotruss.sh:61 msgid "%s: option is ambiguous; possibilities:" @@ -1507,7 +1503,6 @@ msgid "unknown iconv() error %d" msgstr "tuntematon iconv()-virhe %d" #: iconv/iconv_prog.c:791 -#, fuzzy msgid "" "The following list contains all the coded character sets known. This does\n" "not necessarily mean that all combinations of these names can be used for\n" @@ -1516,9 +1511,9 @@ msgid "" "\n" " " msgstr "" -"Seuraavassa listassa ovat kaikki tunnetut koodatut merkistöt. Se ei\n" +"Seuraavassa listassa ovat kaikki tunnetut koodatut merkistöt. Tämä ei\n" "kuitenkaan välttämättä tarkoita sitä, että kaikkia näiden nimien\n" -"yhdistelmiä voidaan käyttää FROM- ja TO-komentoriviparametreina. Yksi\n" +"yhdistelmiä voisi käyttää FROM- ja TO-komentoriviparametreina. Yksi\n" "koodattu merkistö voi olla listalla useilla eri nimillä (aliaksilla).\n" "\n" " " @@ -2733,14 +2728,12 @@ msgid "locale.alias file to consult when making archive" msgstr "Arkistoa luotaessa käytettävä locale.alias-tiedosto" #: locale/programs/localedef.c:150 -#, fuzzy msgid "Generate little-endian output" -msgstr "Tuota little-endian-koodia" +msgstr "Tuota little-endian-muotoa" #: locale/programs/localedef.c:152 -#, fuzzy msgid "Generate big-endian output" -msgstr "Tuota big-endian-koodia" +msgstr "Tuota big-endian-muotoa" #: locale/programs/localedef.c:157 msgid "Compile locale specification" @@ -4275,10 +4268,9 @@ msgid "" msgstr "" #: nscd/nscd.c:635 -#, fuzzy, c-format -#| msgid "lstat failed" +#, c-format msgid "'wait' failed\n" -msgstr "tiedoston tilan luku epäonnistui" +msgstr "”wait” epäonnistui\n" #: nscd/nscd.c:642 #, c-format @@ -4670,9 +4662,9 @@ msgid "cannot create temporary file" msgstr "tilapäistä tiedostoa ei voi luoda" #: nss/makedb.c:304 -#, fuzzy, c-format +#, c-format msgid "cannot stat newly created file" -msgstr "tiedoston ”%s” tilaa ei voi lukea: %s" +msgstr "juuri luodun tiedoston tilaa ei voi lukea" #: nss/makedb.c:315 #, c-format @@ -4680,9 +4672,9 @@ msgid "cannot rename temporary file" msgstr "tilapäistä tiedostoa ei voi nimetä uudelleen" #: nss/makedb.c:531 nss/makedb.c:554 -#, fuzzy, c-format +#, c-format msgid "cannot create search tree" -msgstr "hakupolulle ei voi luoda välimuistia" +msgstr "hakupuuta ei voi luoda" #: nss/makedb.c:560 msgid "duplicate key" @@ -4699,9 +4691,9 @@ msgid "failed to write new database file" msgstr "uuden tietokantatiedoston kirjoittaminen epäonnistui" #: nss/makedb.c:812 -#, fuzzy, c-format +#, c-format msgid "cannot stat database file" -msgstr "tiedoston ”%s” tilaa ei voi lukea: %s" +msgstr "tietokantatiedoston tilaa ei voi lukea" #: nss/makedb.c:817 #, fuzzy, c-format @@ -4709,9 +4701,9 @@ msgid "cannot map database file" msgstr "Karttatietokannassa ei ole enempää tietueita" #: nss/makedb.c:820 -#, fuzzy, c-format +#, c-format msgid "file not a database file" -msgstr "luettaessa profilointidatatiedoston tilaa" +msgstr "tiedosto ei ole tietokantatiedosto" #: nss/makedb.c:871 #, fuzzy, c-format @@ -4726,7 +4718,7 @@ msgstr "Käyttö: %s [-v määrittely] muuttujanimi [polku]\n" #: posix/getconf.c:403 #, c-format msgid " %s -a [pathname]\n" -msgstr "" +msgstr " %s -a [polku]\n" #: posix/getconf.c:479 #, c-format @@ -5094,11 +5086,11 @@ msgstr "Laitetta irrotettu" #: stdio-common/psiginfo.c:139 msgid "Signal sent by kill()" -msgstr "" +msgstr "Signaalin lähetti kill()" #: stdio-common/psiginfo.c:142 msgid "Signal sent by sigqueue()" -msgstr "" +msgstr "Signaalin lähetti sigqueue()" #: stdio-common/psiginfo.c:145 msgid "Signal generated by the expiration of a timer" @@ -5114,7 +5106,7 @@ msgstr "" #: stdio-common/psiginfo.c:157 msgid "Signal sent by tkill()" -msgstr "" +msgstr "Signaalin lähetti tkill()" #: stdio-common/psiginfo.c:162 msgid "Signal generated by the completion of an asynchronous name lookup request" @@ -5296,9 +5288,8 @@ msgid "Failed (unspecified error)" msgstr "Epäonnistui (määrittelemätön virhe)" #: sunrpc/clnt_raw.c:115 -#, fuzzy msgid "clnt_raw.c: fatal header serialization error" -msgstr "clnt_raw.c: vakava otsikon serialisointivirhe" +msgstr "clnt_raw.c: vakava otsikon sarjallistamisvirhe" #: sunrpc/pm_getmaps.c:77 msgid "pmap_getmaps.c: rpc problem" @@ -6825,9 +6816,8 @@ msgid "Interrupted by a signal" msgstr "Signaalin keskeyttämä" #: sysdeps/posix/gai_strerror-strs.h:17 -#, fuzzy msgid "Parameter string not correctly encoded" -msgstr "Parametrimerkkijono on väärin koodattu" +msgstr "Parametrimerkkijono ei ole koodattu oikein" #: sysdeps/unix/sysv/linux/i386/readelflib.c:65 #, c-format diff --git a/po/sv.po b/po/sv.po index 49d1f23904..e046577b08 100644 --- a/po/sv.po +++ b/po/sv.po @@ -1,13 +1,17 @@ # GNU libc message catalog for Swedish -# Copyright © 1996, 1998, 2001, 2002, 2003, 2006, 2008, 2009, 2011, 2012, 2013, 2014, 2015 Free Software Foundation, Inc. +# Copyright © 1996, 1998, 2001, 2002, 2003, 2006, 2008, 2009, 2011, 2012, 2013, 2014, 2015, 2016 Free Software Foundation, Inc. # This file is distributed under the same license as the glibc package. -# Jan Djärv , 1996, 1998, 2001, 2002, 2003, 2006, 2007, 2008, 2009, 2011, 2012, 2013, 2014, 2015 +# +# Jan Djärv , 1996, 1998, 2001, 2002, 2003, 2006, 2007, 2008, 2009, 2011, 2012, 2013, 2014, 2015. +# Göran Uddeborg , 2016. +# +# $Revision: 1.3 $ msgid "" msgstr "" -"Project-Id-Version: libc 2.21-pre1\n" +"Project-Id-Version: libc 2.22-pre1\n" "POT-Creation-Date: 2015-07-31 00:10-0400\n" -"PO-Revision-Date: 2015-01-24 10:35+0100\n" -"Last-Translator: Jan Djärv \n" +"PO-Revision-Date: 2016-08-02 17:17+0200\n" +"Last-Translator: Göran Uddeborg \n" "Language-Team: Swedish \n" "Language: sv\n" "MIME-Version: 1.0\n" @@ -48,7 +52,7 @@ msgstr " [FLAGGA...]" #: argp/argp-help.c:1643 #, c-format msgid "Try `%s --help' or `%s --usage' for more information.\n" -msgstr "Försök med \"%s --help\" eller \"%s --usage\" för mer information\n" +msgstr "Försök med ”%s --help” eller ”%s --usage” för mer information.\n" #: argp/argp-help.c:1671 #, c-format @@ -304,11 +308,11 @@ msgstr "Användning: xtrace [FLAGGA]... PROGRAM [PROGRAMFLAGGA}...\\n" #: debug/xtrace.sh:32 elf/sotruss.sh:56 elf/sotruss.sh:67 elf/sotruss.sh:135 #: malloc/memusage.sh:26 msgid "Try \\`%s --help' or \\`%s --usage' for more information.\\n" -msgstr "Försök med \\\"%s --help\\\" eller \\\"%s --usage\\\" för mer information\\n" +msgstr "Försök med ”%s --help” eller ”%s --usage” för mer information\\n" #: debug/xtrace.sh:38 msgid "%s: option '%s' requires an argument.\\n" -msgstr "%s: flaggan \\\"%s\\\" kräver ett argument\\n" +msgstr "%s: flaggan ”%s” kräver ett argument.\\n" #: debug/xtrace.sh:45 msgid "" @@ -332,19 +336,17 @@ msgstr "" " --usage Visa en kort hjälptext\n" " -V,--version Visa versionsinformation och avsluta\n" "\n" -"Obligatoriska argument för långa flaggor är obligatoriska även för\n" +"Obligatoriska argument för långa flaggor är obligatoriska även för\n" "motsvarande korta.\n" #: debug/xtrace.sh:57 elf/ldd.bash.in:55 elf/sotruss.sh:49 #: malloc/memusage.sh:64 msgid "For bug reporting instructions, please see:\\\\n%s.\\\\n" -msgstr "" -"För felrapporteringsinstruktioner, se:\\\\n%s.\\\\n\n" -"Rapportera fel eller synpunkter på översättningen till .\\\\n" +msgstr "För felrapporteringsinstruktioner, se:\\\\n%s.\\\\nRapportera fel eller synpunkter på översättningen till:\\\\n.\\\\n" #: debug/xtrace.sh:125 msgid "xtrace: unrecognized option \\`$1'\\n" -msgstr "xtrace: okänd flagga \"$1\"\\n" +msgstr "xtrace: okänd flagga ”$1”\\n" #: debug/xtrace.sh:138 msgid "No program name given\\n" @@ -353,12 +355,12 @@ msgstr "Inget programnamn givet\\n" #: debug/xtrace.sh:146 #, sh-format msgid "executable \\`$program' not found\\n" -msgstr "program \"$program\" hittades inte\\n" +msgstr "program ”$program” hittades inte\\n" #: debug/xtrace.sh:150 #, sh-format msgid "\\`$program' is no executable\\n" -msgstr "\"$program\" är inte en körbar binär\\n" +msgstr "”$program” är inte en körbar binär\\n" #: dlfcn/dlinfo.c:63 msgid "RTLD_SELF used in code not dynamically loaded" @@ -396,7 +398,7 @@ msgstr ", OS ABI: %s %d.%d.%d" #: elf/cache.c:157 elf/ldconfig.c:1340 #, c-format msgid "Can't open cache file %s\n" -msgstr "Kan inte öppna cache-fil \"%s\"\n" +msgstr "Kan inte öppna cache-filen %s\n" #: elf/cache.c:171 #, c-format @@ -416,7 +418,7 @@ msgstr "%d bibliotek hittades i cache \"%s\"\n" #: elf/cache.c:426 #, c-format msgid "Can't create temporary cache file %s" -msgstr "Kan inte skapa temporär cache-fil \"%s\"" +msgstr "Kan inte skapa en temporär cache-fil %s" #: elf/cache.c:434 elf/cache.c:444 elf/cache.c:448 elf/cache.c:453 #, c-format @@ -829,7 +831,7 @@ msgstr "Kan inte ta status (lstat) på %s" #: elf/ldconfig.c:609 #, c-format msgid "Ignored file %s since it is not a regular file." -msgstr "Ignorerar fil %s eftersom den inte är en vanlig fil" +msgstr "Ignorerar fil %s eftersom den inte är en vanlig fil." #: elf/ldconfig.c:618 #, c-format @@ -951,7 +953,7 @@ msgstr "" #: elf/ldd.bash.in:80 msgid "ldd: option \\`$1' is ambiguous" -msgstr "ldd: flaggan \"$1\" är tvetydig" +msgstr "ldd: flaggan ”$1” är tvetydig" #: elf/ldd.bash.in:87 msgid "unrecognized option" @@ -959,7 +961,7 @@ msgstr "okänd flagga" #: elf/ldd.bash.in:88 elf/ldd.bash.in:125 msgid "Try \\`ldd --help' for more information." -msgstr "Försök med \"ldd --help\" för mer information" +msgstr "Försök med \"ldd --help\" för mer information." #: elf/ldd.bash.in:124 msgid "missing file arguments" @@ -1028,10 +1030,9 @@ msgid "cannot read object name" msgstr "kan inte läsa objektnamn" #: elf/pldd-xx.c:219 -#, fuzzy, c-format -#| msgid "cannot allocate memory for program header" +#, c-format msgid "cannot allocate buffer for object name" -msgstr "kan inte allokera minne för programhuvud" +msgstr "kan inte allokera en buffert för objektnamn" #: elf/pldd.c:64 msgid "List dynamic shared objects loaded into process." @@ -1212,11 +1213,11 @@ msgstr "" #: elf/sotruss.sh:46 msgid "Mandatory arguments to long options are also mandatory for any corresponding\\nshort options.\\n" -msgstr "Obligatoriska respektive valfria argument för långa flaggor är obligatoriska respektive\\nvalfria även för korta.\\n" +msgstr "Obligatoriska respektive valfria argument för långa flaggor är obligatoriska\\nrespektive valfria även för korta.\\n" #: elf/sotruss.sh:55 msgid "%s: option requires an argument -- '%s'\\n" -msgstr "%s: flaggan kräver ett argument -- \\\"%s\\\"\\n" +msgstr "%s: flaggan kräver ett argument — ”%s”\\n" #: elf/sotruss.sh:61 msgid "%s: option is ambiguous; possibilities:" @@ -1240,7 +1241,7 @@ msgstr "" #: elf/sotruss.sh:134 msgid "%s: unrecognized option '%c%s'\\n" -msgstr "%s: okänd flagga \\\"%c%s\\\"\\n" +msgstr "%s: okänd flagga ”%c%s”\\n" #: elf/sprof.c:77 msgid "Output selection:" @@ -1260,7 +1261,7 @@ msgstr "generera anropsgraf" #: elf/sprof.c:89 msgid "Read and display shared object profiling data." -msgstr "Läs och visa profildata för delat objekt" +msgstr "Läs och visa profildata för delat objekt." #: elf/sprof.c:94 msgid "SHOBJ [PROFDATA]" @@ -1622,7 +1623,7 @@ msgstr "Fel: .netrc kan läsas av andra." #: inet/ruserpass.c:185 msgid "Remove password or make file unreadable by others." -msgstr "Ta bort lösenord eller gör filen oläsbar för andra" +msgstr "Ta bort lösenord eller gör filen oläsbar för andra." #: inet/ruserpass.c:277 #, c-format @@ -2182,12 +2183,12 @@ msgstr "Inget namn definierat i teckenuppsättning" #: locale/programs/ld-ctype.c:479 #, c-format msgid "character L'\\u%0*x' in class `%s' must be in class `%s'" -msgstr "tecken L\"\\u%0*x\" i klass \"%s\" måste vara i klass \"%s\"" +msgstr "tecken L'\\u%0*x' i klassen ”%s” måste vara i klassen ”%s”" #: locale/programs/ld-ctype.c:494 #, c-format msgid "character L'\\u%0*x' in class `%s' must not be in class `%s'" -msgstr "tecken L\"\\u%0*x\" i klass \"%s\" får inte vara i klass \"%s\"" +msgstr "tecken L'\\u%0*x' i klassen ”%s” får inte vara i klassen ”%s”" #: locale/programs/ld-ctype.c:508 locale/programs/ld-ctype.c:566 #, c-format @@ -2611,7 +2612,7 @@ msgstr "Skriv mer information" #: locale/programs/locale.c:85 msgid "Get locale-specific information." -msgstr "Hämta lokalspecifik information" +msgstr "Hämta lokalspecifik information." #: locale/programs/locale.c:88 msgid "" @@ -3022,7 +3023,7 @@ msgstr "felaktig mcheck_status, biblioteket är felaktigt\n" #: malloc/memusage.sh:32 msgid "%s: option '%s' requires an argument\\n" -msgstr "%s: flaggan \\\"%s\\\" kräver ett argument\\n" +msgstr "%s: flaggan ”%s” kräver ett argument\\n" #: malloc/memusage.sh:38 msgid "" @@ -3091,11 +3092,11 @@ msgstr "" #: malloc/memusage.sh:191 msgid "memusage: option \\`${1##*=}' is ambiguous" -msgstr "memusage: flaggan \"${1##*=}\" är tvetydig" +msgstr "memusage: flaggan ”${1##*=}” är tvetydig" #: malloc/memusage.sh:200 msgid "memusage: unrecognized option \\`$1'" -msgstr "memusage: okänd flagga \"$1\"" +msgstr "memusage: okänd flagga ”$1”" #: malloc/memusage.sh:213 msgid "No program name given" @@ -3341,7 +3342,7 @@ msgstr "Kan inte skapa process hos server" #: nis/nis_error.h:48 msgid "Master server busy, full dump rescheduled." -msgstr "Huvudserver är upptagen, full dump åter schemalagd" +msgstr "Huvudserver är upptagen, full dump åter schemalagd." #: nis/nis_local_names.c:121 #, c-format @@ -3511,7 +3512,7 @@ msgstr "\t\tRättigheter : " #: nis/nis_print.c:290 msgid "Linked Object Type : " -msgstr "Länkad objekttyp: " +msgstr "Länkad objekttyp : " #: nis/nis_print.c:292 #, c-format @@ -3802,15 +3803,14 @@ msgid " (first)" msgstr " (första)" #: nscd/cache.c:288 -#, fuzzy, c-format -#| msgid "cannot stat() file `%s': %s" +#, c-format msgid "checking for monitored file `%s': %s" -msgstr "kan inte ta status på fil \"%s\": %s" +msgstr "kontrollerar den övervakade filen ”%s”: %s" #: nscd/cache.c:298 #, c-format msgid "monitored file `%s` changed (mtime)" -msgstr "" +msgstr "den övervakade filen ”%s” ändrades (mtime)" #: nscd/cache.c:341 #, c-format @@ -3906,34 +3906,32 @@ msgstr "kan inte få uttag (socket) att acceptera förbindelser: %s" #: nscd/connections.c:973 #, c-format msgid "disabled inotify-based monitoring for file `%s': %s" -msgstr "" +msgstr "avaktiverade inotify-baserad övervakning för filen ”%s”: %s" #: nscd/connections.c:977 #, c-format msgid "monitoring file `%s` (%d)" -msgstr "" +msgstr "övervakar filen ”%s” (%d)" #: nscd/connections.c:990 #, c-format msgid "disabled inotify-based monitoring for directory `%s': %s" -msgstr "" +msgstr "avaktiverade inotify-baserad övervakning av katalogen ”%s”: %s" #: nscd/connections.c:994 -#, fuzzy, c-format -#| msgid "Can't open directory %s" +#, c-format msgid "monitoring directory `%s` (%d)" -msgstr "Kan inte öppna katalog %s" +msgstr "övervakar katalogen ”%s” (%d)" #: nscd/connections.c:1022 -#, fuzzy, c-format -#| msgid "register trace file %s for database %s" +#, c-format msgid "monitoring file %s for database %s" -msgstr "registrera spårningsfil %s för databas %s" +msgstr "övervakar filen %s för databas %s" #: nscd/connections.c:1032 #, c-format msgid "stat failed for file `%s'; will try again later: %s" -msgstr "" +msgstr "stat misslyckades för filen ”%s”; kommer försöka igen senare: %s" #: nscd/connections.c:1151 #, c-format @@ -4032,44 +4030,42 @@ msgstr "handle_request: begäran mottagen (Version = %d)" #: nscd/connections.c:1963 #, c-format msgid "ignored inotify event for `%s` (file exists)" -msgstr "" +msgstr "ignorerade inotify-händelse för ”%s” (filen finns)" #: nscd/connections.c:1968 #, c-format msgid "monitored file `%s` was %s, removing watch" -msgstr "" +msgstr "den övervakade filen ”%s” var %s, tar bort vakten" #: nscd/connections.c:1976 nscd/connections.c:2018 #, c-format msgid "failed to remove file watch `%s`: %s" -msgstr "" +msgstr "misslyckades att ta bort filvakt ”%s”: %s" #: nscd/connections.c:1991 #, c-format msgid "monitored file `%s` was written to" -msgstr "" +msgstr "den övervakade filen ”%s” skrevs till" #: nscd/connections.c:2015 #, c-format msgid "monitored parent directory `%s` was %s, removing watch on `%s`" -msgstr "" +msgstr "den övervakade föräldrakatalogen ”%s” var %s, tar bort vakten av ”%s”" #: nscd/connections.c:2041 #, c-format msgid "monitored file `%s` was %s, adding watch" -msgstr "" +msgstr "den övervakade filen ”%s” var %s, lägger till vakt" #: nscd/connections.c:2053 -#, fuzzy, c-format -#| msgid "failed to load shared object `%s'" +#, c-format msgid "failed to add file watch `%s`: %s" -msgstr "misslyckades med att ladda delat objekt \"%s\"" +msgstr "misslyckades med att lägga till filvakt ”%s”: %s" #: nscd/connections.c:2247 nscd/connections.c:2428 -#, fuzzy, c-format -#| msgid "disabled inotify after read error %d" +#, c-format msgid "disabled inotify-based monitoring after read error %d" -msgstr "inaktiverade inotify efter läsfel %d" +msgstr "avaktiverade inotify-baserad övervakning efter läsfel %d" #: nscd/connections.c:2543 msgid "could not initialize conditional variable" @@ -4199,7 +4195,7 @@ msgstr "Använd separat cache för varje användare" #: nscd/nscd.c:122 msgid "Name Service Cache Daemon." -msgstr "Namntjänst cache-demon" +msgstr "Cache-demon för namntjänsten." #: nscd/nscd.c:155 nss/getent.c:1007 nss/makedb.c:206 #, c-format @@ -4531,11 +4527,11 @@ msgstr "Access Vector Cache (AVC) startad" #: nscd/selinux.c:368 msgid "Error querying policy for undefined object classes or permissions." -msgstr "Fel när policy för odefinierade objektklasser eller rättigheter hämtades" +msgstr "Fel när policy för odefinierade objektklasser eller rättigheter hämtades." #: nscd/selinux.c:375 msgid "Error getting security class for nscd." -msgstr "Fel när säkerhetsklass för nscd hämtades" +msgstr "Fel när säkerhetsklass för nscd hämtades." #: nscd/selinux.c:380 #, c-format @@ -4609,7 +4605,7 @@ msgstr "inaktivera DIN-kodning" #: nss/getent.c:64 msgid "Get entries from administrative database." -msgstr "Hämta poster från den administrativa databasen" +msgstr "Hämta poster från den administrativa databasen." #: nss/getent.c:148 nss/getent.c:477 nss/getent.c:522 #, c-format @@ -4652,7 +4648,7 @@ msgstr "Genererad rad som inte ingår i iterationen" #: nss/makedb.c:131 msgid "Create simple database from textual input." -msgstr "Skapa en enkel databas från textuell indata" +msgstr "Skapa en enkel databas från textuell indata." #: nss/makedb.c:134 msgid "" @@ -5412,7 +5408,7 @@ msgstr "Kan inte ange netid-flaggan utan TIRPC!\n" #: sunrpc/rpc_main.c:1374 #, c-format msgid "Cannot use table flags with newstyle!\n" -msgstr "Kan inte ange tabellflaggor med ny stil\n" +msgstr "Kan inte ange tabellflaggor med ny stil!\n" #: sunrpc/rpc_main.c:1393 #, c-format @@ -7270,18 +7266,9 @@ msgstr "tidszonsförkortning skiljer sig från POSIX-standarden" #: timezone/zic.c:2789 msgid "too many, or too long, time zone abbreviations" -msgstr "för många eller för långa tidszonförkortningar" +msgstr "för många eller för långa tidszonsförkortningar" #: timezone/zic.c:2829 #, c-format msgid "%s: Can't create directory %s: %s\n" msgstr "%s: Kan inte skapa katalog %s: %s\n" - -#~ msgid "cannot load any more object with static TLS" -#~ msgstr "kan inte ladda fler objekt med statiskt TLS" - -#~ msgid "%s: no PLTREL found in object %s\n" -#~ msgstr "%s: hittade inga PLTREL i objekt %s\n" - -#~ msgid "cannot create internal descriptors" -#~ msgstr "kan inte skapa interna deskriptorer" diff --git a/posix/Makefile b/posix/Makefile index 5b0e298f75..82a4020c76 100644 --- a/posix/Makefile +++ b/posix/Makefile @@ -43,7 +43,7 @@ routines := \ getpgid setpgid getpgrp bsd-getpgrp setpgrp getsid setsid \ getresuid getresgid setresuid setresgid \ pathconf sysconf fpathconf \ - glob glob64 fnmatch regex \ + glob glob64 globfree globfree64 glob_pattern_p fnmatch regex \ confstr \ getopt getopt1 getopt_init \ sched_setp sched_getp sched_sets sched_gets sched_yield sched_primax \ @@ -90,7 +90,7 @@ tests := tstgetopt testfnm runtests runptests \ bug-getopt5 tst-getopt_long1 bug-regex34 bug-regex35 \ tst-pathconf tst-getaddrinfo4 tst-rxspencer-no-utf8 \ tst-fnmatch3 bug-regex36 tst-getaddrinfo5 \ - tst-posix_spawn-fd + tst-posix_spawn-fd tst-glob-tilde xtests := bug-ga2 ifeq (yes,$(build-shared)) test-srcs := globtest @@ -133,7 +133,8 @@ tests-special += $(objpfx)bug-regex2-mem.out $(objpfx)bug-regex14-mem.out \ $(objpfx)tst-rxspencer-no-utf8-mem.out $(objpfx)tst-pcre-mem.out \ $(objpfx)tst-boost-mem.out $(objpfx)tst-getconf.out \ $(objpfx)bug-glob2-mem.out $(objpfx)tst-vfork3-mem.out \ - $(objpfx)tst-fnmatch-mem.out $(objpfx)bug-regex36-mem.out + $(objpfx)tst-fnmatch-mem.out $(objpfx)bug-regex36-mem.out \ + $(objpfx)tst-glob-tilde-mem.out xtests-special += $(objpfx)bug-ga2-mem.out endif @@ -340,6 +341,12 @@ $(objpfx)bug-glob2-mem.out: $(objpfx)bug-glob2.out $(common-objpfx)malloc/mtrace $(objpfx)bug-glob2.mtrace > $@; \ $(evaluate-test) +tst-glob-tilde-ENV = MALLOC_TRACE=$(objpfx)tst-glob-tilde.mtrace + +$(objpfx)tst-glob-tilde-mem.out: $(objpfx)tst-glob-tilde.out + $(common-objpfx)malloc/mtrace $(objpfx)tst-glob-tilde.mtrace > $@; \ + $(evaluate-test) + $(inst_libexecdir)/getconf: $(inst_bindir)/getconf \ $(objpfx)getconf.speclist FORCE $(addprefix $(..)./scripts/mkinstalldirs ,\ diff --git a/posix/execvpe.c b/posix/execvpe.c index d933f9c92a..7cdb06a611 100644 --- a/posix/execvpe.c +++ b/posix/execvpe.c @@ -48,12 +48,13 @@ maybe_script_execute (const char *file, char *const argv[], char *const envp[]) } } - /* Construct an argument list for the shell. */ + /* Construct an argument list for the shell. It will contain at minimum 3 + arguments (current shell, script, and an ending NULL. */ char *new_argv[argc + 1]; new_argv[0] = (char *) _PATH_BSHELL; new_argv[1] = (char *) file; if (argc > 1) - memcpy (new_argv + 2, argv + 1, argc * sizeof(char *)); + memcpy (new_argv + 2, argv + 1, (argc - 1) * sizeof(char *)); else new_argv[2] = NULL; @@ -91,10 +92,11 @@ __execvpe (const char *file, char *const argv[], char *const envp[]) /* Although GLIBC does not enforce NAME_MAX, we set it as the maximum size to avoid unbounded stack allocation. Same applies for PATH_MAX. */ - size_t file_len = __strnlen (file, NAME_MAX + 1); + size_t file_len = __strnlen (file, NAME_MAX) + 1; size_t path_len = __strnlen (path, PATH_MAX - 1) + 1; - if ((file_len > NAME_MAX) + /* NAME_MAX does not include the terminating null character. */ + if (((file_len-1) > NAME_MAX) || !__libc_alloca_cutoff (path_len + file_len + 1)) { errno = ENAMETOOLONG; @@ -103,6 +105,9 @@ __execvpe (const char *file, char *const argv[], char *const envp[]) const char *subp; bool got_eacces = false; + /* The resulting string maximum size would be potentially a entry + in PATH plus '/' (path_len + 1) and then the the resulting file name + plus '\0' (file_len since it already accounts for the '\0'). */ char buffer[path_len + file_len + 1]; for (const char *p = path; ; p = subp) { @@ -123,7 +128,7 @@ __execvpe (const char *file, char *const argv[], char *const envp[]) execute. */ char *pend = mempcpy (buffer, p, subp - p); *pend = '/'; - memcpy (pend + (p < subp), file, file_len + 1); + memcpy (pend + (p < subp), file, file_len); __execve (buffer, argv, envp); diff --git a/posix/flexmember.h b/posix/flexmember.h new file mode 100644 index 0000000000..107c1f09e9 --- /dev/null +++ b/posix/flexmember.h @@ -0,0 +1,45 @@ +/* Sizes of structs with flexible array members. + + Copyright 2016-2017 Free Software Foundation, Inc. + + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . + + Written by Paul Eggert. */ + +#include + +/* Nonzero multiple of alignment of TYPE, suitable for FLEXSIZEOF below. + On older platforms without _Alignof, use a pessimistic bound that is + safe in practice even if FLEXIBLE_ARRAY_MEMBER is 1. + On newer platforms, use _Alignof to get a tighter bound. */ + +#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112 +# define FLEXALIGNOF(type) (sizeof (type) & ~ (sizeof (type) - 1)) +#else +# define FLEXALIGNOF(type) _Alignof (type) +#endif + +/* Upper bound on the size of a struct of type TYPE with a flexible + array member named MEMBER that is followed by N bytes of other data. + This is not simply sizeof (TYPE) + N, since it may require + alignment on unusually picky C11 platforms, and + FLEXIBLE_ARRAY_MEMBER may be 1 on pre-C11 platforms. + Yield a value less than N if and only if arithmetic overflow occurs. */ + +#define FLEXSIZEOF(type, member, n) \ + ((offsetof (type, member) + FLEXALIGNOF (type) - 1 + (n)) \ + & ~ (FLEXALIGNOF (type) - 1)) diff --git a/posix/glob.c b/posix/glob.c index ea4b0b61eb..f3fa807700 100644 --- a/posix/glob.c +++ b/posix/glob.c @@ -15,7 +15,7 @@ License along with the GNU C Library; if not, see . */ -#ifdef HAVE_CONFIG_H +#ifndef _LIBC # include #endif @@ -27,29 +27,15 @@ #include #include #include - -/* Outcomment the following line for production quality code. */ -/* #define NDEBUG 1 */ #include +#include -#include /* Needed on stupid SunOS for assert. */ - -#if !defined _LIBC || !defined GLOB_ONLY_P -#if defined HAVE_UNISTD_H || defined _LIBC -# include -# ifndef POSIX -# ifdef _POSIX_VERSION -# define POSIX -# endif -# endif +#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ +# define WINDOWS32 #endif -#include - -#if defined HAVE_STDINT_H || defined _LIBC -# include -#elif !defined UINTPTR_MAX -# define UINTPTR_MAX (~((size_t) 0)) +#ifndef WINDOWS32 +# include #endif #include @@ -57,24 +43,7 @@ # define __set_errno(val) errno = (val) #endif -#if defined HAVE_DIRENT_H || defined __GNU_LIBRARY__ -# include -#else -# define dirent direct -# ifdef HAVE_SYS_NDIR_H -# include -# endif -# ifdef HAVE_SYS_DIR_H -# include -# endif -# ifdef HAVE_NDIR_H -# include -# endif -# ifdef HAVE_VMSDIR_H -# include "vmsdir.h" -# endif /* HAVE_VMSDIR_H */ -#endif - +#include #include #include #include @@ -87,27 +56,29 @@ # define opendir(name) __opendir (name) # define readdir(str) __readdir64 (str) # define getpwnam_r(name, bufp, buf, len, res) \ - __getpwnam_r (name, bufp, buf, len, res) + __getpwnam_r (name, bufp, buf, len, res) # ifndef __stat64 # define __stat64(fname, buf) __xstat64 (_STAT_VER, fname, buf) # endif # define struct_stat64 struct stat64 +# define FLEXIBLE_ARRAY_MEMBER #else /* !_LIBC */ -# include "getlogin_r.h" -# include "mempcpy.h" -# include "stat-macros.h" -# include "strdup.h" -# define __stat64(fname, buf) stat (fname, buf) -# define struct_stat64 struct stat -# define __stat(fname, buf) stat (fname, buf) -# define __alloca alloca -# define __readdir readdir -# define __readdir64 readdir64 -# define __glob_pattern_p glob_pattern_p +# define __getlogin_r(buf, len) getlogin_r (buf, len) +# define __stat64(fname, buf) stat (fname, buf) +# define __fxstatat64(_, d, f, st, flag) fstatat (d, f, st, flag) +# define struct_stat64 struct stat +# ifndef __MVS__ +# define __alloca alloca +# endif +# define __readdir readdir +# define COMPILE_GLOB64 #endif /* _LIBC */ #include +#include +#include + #ifdef _SC_GETPW_R_SIZE_MAX # define GETPW_R_SIZE_MAX() sysconf (_SC_GETPW_R_SIZE_MAX) #else @@ -121,61 +92,59 @@ static const char *next_brace_sub (const char *begin, int flags) __THROWNL; +typedef uint_fast8_t dirent_type; + +#if !defined _LIBC && !defined HAVE_STRUCT_DIRENT_D_TYPE +/* Any distinct values will do here. + Undef any existing macros out of the way. */ +# undef DT_UNKNOWN +# undef DT_DIR +# undef DT_LNK +# define DT_UNKNOWN 0 +# define DT_DIR 1 +# define DT_LNK 2 +#endif + /* A representation of a directory entry which does not depend on the layout of struct dirent, or the size of ino_t. */ struct readdir_result { const char *name; -# if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE - uint8_t type; -# endif +#if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE + dirent_type type; +#endif +#if defined _LIBC || defined D_INO_IN_DIRENT bool skip_entry; +#endif }; -# if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE -/* Initializer based on the d_type member of struct dirent. */ -# define D_TYPE_TO_RESULT(source) (source)->d_type, - -/* True if the directory entry D might be a symbolic link. */ -static bool -readdir_result_might_be_symlink (struct readdir_result d) -{ - return d.type == DT_UNKNOWN || d.type == DT_LNK; -} - -/* True if the directory entry D might be a directory. */ -static bool -readdir_result_might_be_dir (struct readdir_result d) -{ - return d.type == DT_DIR || readdir_result_might_be_symlink (d); -} -# else /* defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE */ -# define D_TYPE_TO_RESULT(source) - -/* If we do not have type information, symbolic links and directories - are always a possibility. */ - -static bool -readdir_result_might_be_symlink (struct readdir_result d) +/* Initialize and return type member of struct readdir_result. */ +static dirent_type +readdir_result_type (struct readdir_result d) { - return true; +#if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE +# define D_TYPE_TO_RESULT(source) (source)->d_type, + return d.type; +#else +# define D_TYPE_TO_RESULT(source) + return DT_UNKNOWN; +#endif } +/* Initialize and return skip_entry member of struct readdir_result. */ static bool -readdir_result_might_be_dir (struct readdir_result d) +readdir_result_skip_entry (struct readdir_result d) { - return true; -} - -# endif /* defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE */ - -# if (defined POSIX || defined WINDOWS32) && !defined __GNU_LIBRARY__ /* Initializer for skip_entry. POSIX does not require that the d_ino field be present, and some systems do not provide it. */ -# define D_INO_TO_RESULT(source) false, -# else -# define D_INO_TO_RESULT(source) (source)->d_ino == 0, -# endif +#if defined _LIBC || defined D_INO_IN_DIRENT +# define D_INO_TO_RESULT(source) (source)->d_ino == 0, + return d.skip_entry; +#else +# define D_INO_TO_RESULT(source) + return false; +#endif +} /* Construct an initializer for a struct readdir_result object from a struct dirent *. No copy of the name is made. */ @@ -186,8 +155,6 @@ readdir_result_might_be_dir (struct readdir_result d) D_INO_TO_RESULT (source) \ } -#endif /* !defined _LIBC || !defined GLOB_ONLY_P */ - /* Call gl_readdir on STREAM. This macro can be overridden to reduce type safety if an old interface version needs to be supported. */ #ifndef GL_READDIR @@ -225,18 +192,55 @@ convert_dirent64 (const struct dirent64 *source) } #endif +#ifndef _LIBC +/* The results of opendir() in this file are not used with dirfd and fchdir, + and we do not leak fds to any single-threaded code that could use stdio, + therefore save some unnecessary recursion in fchdir.c and opendir_safer.c. + FIXME - if the kernel ever adds support for multi-thread safety for + avoiding standard fds, then we should use opendir_safer. */ +# ifdef GNULIB_defined_opendir +# undef opendir +# endif +# ifdef GNULIB_defined_closedir +# undef closedir +# endif -#ifndef attribute_hidden -# define attribute_hidden +/* Just use malloc. */ +# define __libc_use_alloca(n) false +# define alloca_account(len, avar) ((void) (len), (void) (avar), (void *) 0) +# define extend_alloca_account(buf, len, newlen, avar) \ + ((void) (buf), (void) (len), (void) (newlen), (void) (avar), (void *) 0) #endif +/* Set *R = A + B. Return true if the answer is mathematically + incorrect due to overflow; in this case, *R is the low order + bits of the correct answer. */ + +static bool +size_add_wrapv (size_t a, size_t b, size_t *r) +{ +#if 5 <= __GNUC__ && !defined __ICC + return __builtin_add_overflow (a, b, r); +#else + *r = a + b; + return *r < a; +#endif +} + +static bool +glob_use_alloca (size_t alloca_used, size_t len) +{ + size_t size; + return (!size_add_wrapv (alloca_used, len, &size) + && __libc_use_alloca (size)); +} + static int glob_in_dir (const char *pattern, const char *directory, int flags, int (*errfunc) (const char *, int), glob_t *pglob, size_t alloca_used); extern int __glob_pattern_type (const char *pattern, int quote) attribute_hidden; -#if !defined _LIBC || !defined GLOB_ONLY_P static int prefix_array (const char *prefix, char **array, size_t n) __THROWNL; static int collated_compare (const void *, const void *) __THROWNL; @@ -265,16 +269,15 @@ next_brace_sub (const char *cp, int flags) return *cp != '\0' ? cp : NULL; } -#endif /* !defined _LIBC || !defined GLOB_ONLY_P */ /* Do glob searching for PATTERN, placing results in PGLOB. The bits defined above may be set in FLAGS. If a directory cannot be opened or read and ERRFUNC is not nil, it is called with the pathname that caused the error, and the - `errno' value from the failing call; if it returns non-zero - `glob' returns GLOB_ABORTED; if it returns zero, the error is ignored. + 'errno' value from the failing call; if it returns non-zero + 'glob' returns GLOB_ABORTED; if it returns zero, the error is ignored. If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned. - Otherwise, `glob' returns zero. */ + Otherwise, 'glob' returns zero. */ int #ifdef GLOB_ATTRIBUTE GLOB_ATTRIBUTE @@ -292,9 +295,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), int malloc_dirname = 0; glob_t dirs; int retval = 0; -#ifdef _LIBC size_t alloca_used = 0; -#endif if (pattern == NULL || pglob == NULL || (flags & ~__GLOB_FLAGS) != 0) { @@ -308,7 +309,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), flags |= GLOB_ONLYDIR; if (!(flags & GLOB_DOOFFS)) - /* Have to do this so `globfree' knows where to start freeing. It + /* Have to do this so 'globfree' knows where to start freeing. It also makes all the code that uses gl_offs simpler. */ pglob->gl_offs = 0; @@ -350,14 +351,12 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), size_t rest_len; char *onealt; size_t pattern_len = strlen (pattern) - 1; -#ifdef _LIBC - int alloca_onealt = __libc_use_alloca (alloca_used + pattern_len); + int alloca_onealt = glob_use_alloca (alloca_used, pattern_len); if (alloca_onealt) onealt = alloca_account (pattern_len, alloca_used); else -#endif { - onealt = (char *) malloc (pattern_len); + onealt = malloc (pattern_len); if (onealt == NULL) { if (!(flags & GLOB_APPEND)) @@ -377,11 +376,9 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), next = next_brace_sub (begin + 1, flags); if (next == NULL) { - /* It is an illegal expression. */ + /* It is an invalid expression. */ illegal_brace: -#ifdef _LIBC if (__glibc_unlikely (!alloca_onealt)) -#endif free (onealt); return glob (pattern, flags & ~GLOB_BRACE, errfunc, pglob); } @@ -429,9 +426,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), /* If we got an error, return it. */ if (result && result != GLOB_NOMATCH) { -#ifdef _LIBC if (__glibc_unlikely (!alloca_onealt)) -#endif free (onealt); if (!(flags & GLOB_APPEND)) { @@ -450,9 +445,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), assert (next != NULL); } -#ifdef _LIBC if (__glibc_unlikely (!alloca_onealt)) -#endif free (onealt); if (pglob->gl_pathc != firstc) @@ -489,14 +482,16 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), /* Find the filename. */ filename = strrchr (pattern, '/'); + #if defined __MSDOS__ || defined WINDOWS32 - /* The case of "d:pattern". Since `:' is not allowed in + /* The case of "d:pattern". Since ':' is not allowed in file names, we can safely assume that wherever it happens in pattern, it signals the filename part. This is so we could some day support patterns like "[a-z]:foo". */ if (filename == NULL) filename = strchr (pattern, ':'); #endif /* __MSDOS__ || WINDOWS32 */ + dirname_modified = 0; if (filename == NULL) { @@ -521,11 +516,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), } filename = pattern; -#ifdef _AMIGA - dirname = (char *) ""; -#else dirname = (char *) "."; -#endif dirlen = 0; } } @@ -549,22 +540,21 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), char *drive_spec; ++dirlen; - drive_spec = (char *) __alloca (dirlen + 1); + drive_spec = __alloca (dirlen + 1); *((char *) mempcpy (drive_spec, pattern, dirlen)) = '\0'; /* For now, disallow wildcards in the drive spec, to prevent infinite recursion in glob. */ if (__glob_pattern_p (drive_spec, !(flags & GLOB_NOESCAPE))) return GLOB_NOMATCH; - /* If this is "d:pattern", we need to copy `:' to DIRNAME + /* If this is "d:pattern", we need to copy ':' to DIRNAME as well. If it's "d:/pattern", don't remove the slash from "d:/", since "d:" and "d:/" are not the same.*/ } #endif -#ifdef _LIBC - if (__libc_use_alloca (alloca_used + dirlen + 1)) + + if (glob_use_alloca (alloca_used, dirlen + 1)) newp = alloca_account (dirlen + 1, alloca_used); else -#endif { newp = malloc (dirlen + 1); if (newp == NULL) @@ -575,14 +565,17 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), dirname = newp; ++filename; - if (filename[0] == '\0' #if defined __MSDOS__ || defined WINDOWS32 - && dirname[dirlen - 1] != ':' - && (dirlen < 3 || dirname[dirlen - 2] != ':' - || dirname[dirlen - 1] != '/') + bool drive_root = (dirlen > 1 + && (dirname[dirlen - 1] == ':' + || (dirlen > 2 && dirname[dirlen - 2] == ':' + && dirname[dirlen - 1] == '/'))); +#else + bool drive_root = false; #endif - && dirlen > 1) - /* "pattern/". Expand "pattern", appending slashes. */ + + if (filename[0] == '\0' && dirlen > 1 && !drive_root) + /* "pattern/". Expand "pattern", appending slashes. */ { int orig_flags = flags; if (!(flags & GLOB_NOESCAPE) && dirname[dirlen - 1] == '\\') @@ -615,7 +608,6 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), } } -#ifndef VMS if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && dirname[0] == '~') { if (dirname[1] == '\0' || dirname[1] == '/' @@ -625,100 +617,127 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), /* Look up home directory. */ char *home_dir = getenv ("HOME"); int malloc_home_dir = 0; -# ifdef _AMIGA - if (home_dir == NULL || home_dir[0] == '\0') - home_dir = "SYS:"; -# else -# ifdef WINDOWS32 - if (home_dir == NULL || home_dir[0] == '\0') - home_dir = "c:/users/default"; /* poor default */ -# else if (home_dir == NULL || home_dir[0] == '\0') { +#ifdef WINDOWS32 + /* Windows NT defines HOMEDRIVE and HOMEPATH. But give + preference to HOME, because the user can change HOME. */ + const char *home_drive = getenv ("HOMEDRIVE"); + const char *home_path = getenv ("HOMEPATH"); + + if (home_drive != NULL && home_path != NULL) + { + size_t home_drive_len = strlen (home_drive); + size_t home_path_len = strlen (home_path); + char *mem = alloca (home_drive_len + home_path_len + 1); + + memcpy (mem, home_drive, home_drive_len); + memcpy (mem + home_drive_len, home_path, home_path_len + 1); + home_dir = mem; + } + else + home_dir = "c:/users/default"; /* poor default */ +#else int success; char *name; + int malloc_name = 0; size_t buflen = GET_LOGIN_NAME_MAX () + 1; if (buflen == 0) - /* `sysconf' does not support _SC_LOGIN_NAME_MAX. Try + /* 'sysconf' does not support _SC_LOGIN_NAME_MAX. Try a moderate value. */ buflen = 20; - name = alloca_account (buflen, alloca_used); + if (glob_use_alloca (alloca_used, buflen)) + name = alloca_account (buflen, alloca_used); + else + { + name = malloc (buflen); + if (name == NULL) + { + retval = GLOB_NOSPACE; + goto out; + } + malloc_name = 1; + } success = __getlogin_r (name, buflen) == 0; if (success) { struct passwd *p; -# if defined HAVE_GETPWNAM_R || defined _LIBC - long int pwbuflen = GETPW_R_SIZE_MAX (); + char *malloc_pwtmpbuf = NULL; char *pwtmpbuf; +# if defined HAVE_GETPWNAM_R || defined _LIBC + long int pwbuflenmax = GETPW_R_SIZE_MAX (); + size_t pwbuflen = pwbuflenmax; struct passwd pwbuf; - int malloc_pwtmpbuf = 0; int save = errno; -# ifndef _LIBC - if (pwbuflen == -1) - /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX. +# ifndef _LIBC + if (! (0 < pwbuflenmax && pwbuflenmax <= SIZE_MAX)) + /* 'sysconf' does not support _SC_GETPW_R_SIZE_MAX. Try a moderate value. */ pwbuflen = 1024; -# endif - if (__libc_use_alloca (alloca_used + pwbuflen)) +# endif + if (glob_use_alloca (alloca_used, pwbuflen)) pwtmpbuf = alloca_account (pwbuflen, alloca_used); else { pwtmpbuf = malloc (pwbuflen); if (pwtmpbuf == NULL) { + if (__glibc_unlikely (malloc_name)) + free (name); retval = GLOB_NOSPACE; goto out; } - malloc_pwtmpbuf = 1; + malloc_pwtmpbuf = pwtmpbuf; } while (getpwnam_r (name, &pwbuf, pwtmpbuf, pwbuflen, &p) != 0) { + size_t newlen; + bool v; if (errno != ERANGE) { p = NULL; break; } - - if (!malloc_pwtmpbuf - && __libc_use_alloca (alloca_used - + 2 * pwbuflen)) + v = size_add_wrapv (pwbuflen, pwbuflen, &newlen); + if (!v && malloc_pwtmpbuf == NULL + && glob_use_alloca (alloca_used, newlen)) pwtmpbuf = extend_alloca_account (pwtmpbuf, pwbuflen, - 2 * pwbuflen, - alloca_used); + newlen, alloca_used); else { - char *newp = realloc (malloc_pwtmpbuf - ? pwtmpbuf : NULL, - 2 * pwbuflen); + char *newp = (v ? NULL + : realloc (malloc_pwtmpbuf, newlen)); if (newp == NULL) { - if (__glibc_unlikely (malloc_pwtmpbuf)) - free (pwtmpbuf); + free (malloc_pwtmpbuf); + if (__glibc_unlikely (malloc_name)) + free (name); retval = GLOB_NOSPACE; goto out; } - pwtmpbuf = newp; - pwbuflen = 2 * pwbuflen; - malloc_pwtmpbuf = 1; + malloc_pwtmpbuf = pwtmpbuf = newp; } + pwbuflen = newlen; __set_errno (save); } -# else +# else p = getpwnam (name); -# endif +# endif + if (__glibc_unlikely (malloc_name)) + free (name); if (p != NULL) { - if (!malloc_pwtmpbuf) + if (malloc_pwtmpbuf == NULL) home_dir = p->pw_dir; else { size_t home_dir_len = strlen (p->pw_dir) + 1; - if (__libc_use_alloca (alloca_used + home_dir_len)) + if (glob_use_alloca (alloca_used, home_dir_len)) home_dir = alloca_account (home_dir_len, alloca_used); else @@ -733,26 +752,32 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), malloc_home_dir = 1; } memcpy (home_dir, p->pw_dir, home_dir_len); - - free (pwtmpbuf); } } + free (malloc_pwtmpbuf); } + else + { + if (__glibc_unlikely (malloc_name)) + free (name); + } +#endif /* WINDOWS32 */ } if (home_dir == NULL || home_dir[0] == '\0') { + if (__glibc_unlikely (malloc_home_dir)) + free (home_dir); if (flags & GLOB_TILDE_CHECK) { - if (__glibc_unlikely (malloc_home_dir)) - free (home_dir); retval = GLOB_NOMATCH; goto out; } else - home_dir = (char *) "~"; /* No luck. */ + { + home_dir = (char *) "~"; /* No luck. */ + malloc_home_dir = 0; + } } -# endif /* WINDOWS32 */ -# endif /* Now construct the full directory. */ if (dirname[1] == '\0') { @@ -767,8 +792,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), { char *newp; size_t home_len = strlen (home_dir); - int use_alloca = __libc_use_alloca (alloca_used - + home_len + dirlen); + int use_alloca = glob_use_alloca (alloca_used, home_len + dirlen); if (use_alloca) newp = alloca_account (home_len + dirlen, alloca_used); else @@ -792,12 +816,15 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), dirname = newp; dirlen += home_len - 1; malloc_dirname = !use_alloca; + + if (__glibc_unlikely (malloc_home_dir)) + free (home_dir); } dirname_modified = 1; } -# if !defined _AMIGA && !defined WINDOWS32 else { +#ifndef WINDOWS32 char *end_name = strchr (dirname, '/'); char *user_name; int malloc_user_name = 0; @@ -819,7 +846,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), else { char *newp; - if (__libc_use_alloca (alloca_used + (end_name - dirname))) + if (glob_use_alloca (alloca_used, end_name - dirname)) newp = alloca_account (end_name - dirname, alloca_used); else { @@ -836,11 +863,11 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), char *p = mempcpy (newp, dirname + 1, unescape - dirname - 1); char *q = unescape; - while (*q != '\0') + while (q != end_name) { if (*q == '\\') { - if (q[1] == '\0') + if (q + 1 == end_name) { /* "~fo\\o\\" unescape to user_name "foo\\", but "~fo\\o\\/" unescape to user_name @@ -856,7 +883,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), *p = '\0'; } else - *((char *) mempcpy (newp, dirname + 1, end_name - dirname)) + *((char *) mempcpy (newp, dirname + 1, end_name - dirname - 1)) = '\0'; user_name = newp; } @@ -864,20 +891,21 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), /* Look up specific user's home directory. */ { struct passwd *p; + char *malloc_pwtmpbuf = NULL; # if defined HAVE_GETPWNAM_R || defined _LIBC - long int buflen = GETPW_R_SIZE_MAX (); + long int buflenmax = GETPW_R_SIZE_MAX (); + size_t buflen = buflenmax; char *pwtmpbuf; - int malloc_pwtmpbuf = 0; struct passwd pwbuf; int save = errno; # ifndef _LIBC - if (buflen == -1) - /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX. Try a + if (! (0 <= buflenmax && buflenmax <= SIZE_MAX)) + /* Perhaps 'sysconf' does not support _SC_GETPW_R_SIZE_MAX. Try a moderate value. */ buflen = 1024; # endif - if (__libc_use_alloca (alloca_used + buflen)) + if (glob_use_alloca (alloca_used, buflen)) pwtmpbuf = alloca_account (buflen, alloca_used); else { @@ -890,32 +918,32 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), retval = GLOB_NOSPACE; goto out; } - malloc_pwtmpbuf = 1; + malloc_pwtmpbuf = pwtmpbuf; } while (getpwnam_r (user_name, &pwbuf, pwtmpbuf, buflen, &p) != 0) { + size_t newlen; + bool v; if (errno != ERANGE) { p = NULL; break; } - if (!malloc_pwtmpbuf - && __libc_use_alloca (alloca_used + 2 * buflen)) + v = size_add_wrapv (buflen, buflen, &newlen); + if (!v && malloc_pwtmpbuf == NULL + && glob_use_alloca (alloca_used, newlen)) pwtmpbuf = extend_alloca_account (pwtmpbuf, buflen, - 2 * buflen, alloca_used); + newlen, alloca_used); else { - char *newp = realloc (malloc_pwtmpbuf ? pwtmpbuf : NULL, - 2 * buflen); + char *newp = v ? NULL : realloc (malloc_pwtmpbuf, newlen); if (newp == NULL) { - if (__glibc_unlikely (malloc_pwtmpbuf)) - free (pwtmpbuf); + free (malloc_pwtmpbuf); goto nomem_getpw; } - pwtmpbuf = newp; - malloc_pwtmpbuf = 1; + malloc_pwtmpbuf = pwtmpbuf = newp; } __set_errno (save); } @@ -936,7 +964,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), free (dirname); malloc_dirname = 0; - if (__libc_use_alloca (alloca_used + home_len + rest_len + 1)) + if (glob_use_alloca (alloca_used, home_len + rest_len + 1)) dirname = alloca_account (home_len + rest_len + 1, alloca_used); else @@ -944,8 +972,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), dirname = malloc (home_len + rest_len + 1); if (dirname == NULL) { - if (__glibc_unlikely (malloc_pwtmpbuf)) - free (pwtmpbuf); + free (malloc_pwtmpbuf); retval = GLOB_NOSPACE; goto out; } @@ -957,24 +984,24 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), dirlen = home_len + rest_len; dirname_modified = 1; - if (__glibc_unlikely (malloc_pwtmpbuf)) - free (pwtmpbuf); + free (malloc_pwtmpbuf); } else { - if (__glibc_unlikely (malloc_pwtmpbuf)) - free (pwtmpbuf); + free (malloc_pwtmpbuf); if (flags & GLOB_TILDE_CHECK) - /* We have to regard it as an error if we cannot find the - home directory. */ - return GLOB_NOMATCH; + { + /* We have to regard it as an error if we cannot find the + home directory. */ + retval = GLOB_NOMATCH; + goto out; + } } } +#endif /* !WINDOWS32 */ } -# endif /* Not Amiga && not WINDOWS32. */ } -#endif /* Not VMS. */ /* Now test whether we looked for "~" or "~NAME". In this case we can give the answer now. */ @@ -993,19 +1020,18 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), size_t newcount = pglob->gl_pathc + pglob->gl_offs; char **new_gl_pathv; - if (newcount > UINTPTR_MAX - (1 + 1) - || newcount + 1 + 1 > ~((size_t) 0) / sizeof (char *)) + if (newcount > SIZE_MAX / sizeof (char *) - 2) { nospace: free (pglob->gl_pathv); pglob->gl_pathv = NULL; pglob->gl_pathc = 0; - return GLOB_NOSPACE; + retval = GLOB_NOSPACE; + goto out; } - new_gl_pathv - = (char **) realloc (pglob->gl_pathv, - (newcount + 1 + 1) * sizeof (char *)); + new_gl_pathv = realloc (pglob->gl_pathv, + (newcount + 2) * sizeof (char *)); if (new_gl_pathv == NULL) goto nospace; pglob->gl_pathv = new_gl_pathv; @@ -1019,12 +1045,19 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), p = mempcpy (pglob->gl_pathv[newcount], dirname, dirlen); p[0] = '/'; p[1] = '\0'; + if (__glibc_unlikely (malloc_dirname)) + free (dirname); } else { - pglob->gl_pathv[newcount] = strdup (dirname); - if (pglob->gl_pathv[newcount] == NULL) - goto nospace; + if (__glibc_unlikely (malloc_dirname)) + pglob->gl_pathv[newcount] = dirname; + else + { + pglob->gl_pathv[newcount] = strdup (dirname); + if (pglob->gl_pathv[newcount] == NULL) + goto nospace; + } } pglob->gl_pathv[++newcount] = NULL; ++pglob->gl_pathc; @@ -1034,7 +1067,8 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), } /* Not found. */ - return GLOB_NOMATCH; + retval = GLOB_NOMATCH; + goto out; } meta = __glob_pattern_type (dirname, !(flags & GLOB_NOESCAPE)); @@ -1080,7 +1114,10 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), if (status != 0) { if ((flags & GLOB_NOCHECK) == 0 || status != GLOB_NOMATCH) - return status; + { + retval = status; + goto out; + } goto no_matches; } @@ -1091,19 +1128,6 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), { size_t old_pathc; -#ifdef SHELL - { - /* Make globbing interruptible in the bash shell. */ - extern int interrupt_state; - - if (interrupt_state) - { - globfree (&dirs); - return GLOB_ABORTED; - } - } -#endif /* SHELL. */ - old_pathc = pglob->gl_pathc; status = glob_in_dir (filename, dirs.gl_pathv[i], ((flags | GLOB_APPEND) @@ -1118,7 +1142,8 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), globfree (&dirs); globfree (pglob); pglob->gl_pathc = 0; - return status; + retval = status; + goto out; } /* Stick the directory on the front of each name. */ @@ -1129,13 +1154,14 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), globfree (&dirs); globfree (pglob); pglob->gl_pathc = 0; - return GLOB_NOSPACE; + retval = GLOB_NOSPACE; + goto out; } } flags |= GLOB_MAGCHAR; - /* We have ignored the GLOB_NOCHECK flag in the `glob_in_dir' calls. + /* We have ignored the GLOB_NOCHECK flag in the 'glob_in_dir' calls. But if we have not found any matching entry and the GLOB_NOCHECK flag was set we must return the input pattern itself. */ if (pglob->gl_pathc + pglob->gl_offs == oldcount) @@ -1147,28 +1173,28 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), size_t newcount = pglob->gl_pathc + pglob->gl_offs; char **new_gl_pathv; - if (newcount > UINTPTR_MAX - 2 - || newcount + 2 > ~((size_t) 0) / sizeof (char *)) + if (newcount > SIZE_MAX / sizeof (char *) - 2) { nospace2: globfree (&dirs); - return GLOB_NOSPACE; + retval = GLOB_NOSPACE; + goto out; } - new_gl_pathv = (char **) realloc (pglob->gl_pathv, - (newcount + 2) - * sizeof (char *)); + new_gl_pathv = realloc (pglob->gl_pathv, + (newcount + 2) * sizeof (char *)); if (new_gl_pathv == NULL) goto nospace2; pglob->gl_pathv = new_gl_pathv; - pglob->gl_pathv[newcount] = __strdup (pattern); + pglob->gl_pathv[newcount] = strdup (pattern); if (pglob->gl_pathv[newcount] == NULL) { globfree (&dirs); globfree (pglob); pglob->gl_pathc = 0; - return GLOB_NOSPACE; + retval = GLOB_NOSPACE; + goto out; } ++pglob->gl_pathc; @@ -1180,7 +1206,8 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), else { globfree (&dirs); - return GLOB_NOMATCH; + retval = GLOB_NOMATCH; + goto out; } } @@ -1226,7 +1253,8 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), flags = orig_flags; goto no_matches; } - return status; + retval = status; + goto out; } if (dirlen > 0) @@ -1238,7 +1266,8 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), { globfree (pglob); pglob->gl_pathc = 0; - return GLOB_NOSPACE; + retval = GLOB_NOSPACE; + goto out; } } } @@ -1263,7 +1292,8 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), { globfree (pglob); pglob->gl_pathc = 0; - return GLOB_NOSPACE; + retval = GLOB_NOSPACE; + goto out; } strcpy (&new[len - 2], "/"); pglob->gl_pathv[i] = new; @@ -1289,32 +1319,12 @@ libc_hidden_def (glob) #endif -#if !defined _LIBC || !defined GLOB_ONLY_P - -/* Free storage allocated in PGLOB by a previous `glob' call. */ -void -globfree (glob_t *pglob) -{ - if (pglob->gl_pathv != NULL) - { - size_t i; - for (i = 0; i < pglob->gl_pathc; ++i) - free (pglob->gl_pathv[pglob->gl_offs + i]); - free (pglob->gl_pathv); - pglob->gl_pathv = NULL; - } -} -#if defined _LIBC && !defined globfree -libc_hidden_def (globfree) -#endif - - /* Do a collated comparison of A and B. */ static int collated_compare (const void *a, const void *b) { - const char *const s1 = *(const char *const * const) a; - const char *const s2 = *(const char *const * const) b; + char *const *ps1 = a; char *s1 = *ps1; + char *const *ps2 = b; char *s2 = *ps2; if (s1 == s2) return 0; @@ -1335,28 +1345,24 @@ prefix_array (const char *dirname, char **array, size_t n) { size_t i; size_t dirlen = strlen (dirname); -#if defined __MSDOS__ || defined WINDOWS32 - int sep_char = '/'; -# define DIRSEP_CHAR sep_char -#else -# define DIRSEP_CHAR '/' -#endif + char dirsep_char = '/'; if (dirlen == 1 && dirname[0] == '/') /* DIRNAME is just "/", so normal prepending would get us "//foo". We want "/foo" instead, so don't prepend any chars from DIRNAME. */ dirlen = 0; + #if defined __MSDOS__ || defined WINDOWS32 - else if (dirlen > 1) + if (dirlen > 1) { if (dirname[dirlen - 1] == '/' && dirname[dirlen - 2] == ':') /* DIRNAME is "d:/". Don't prepend the slash from DIRNAME. */ --dirlen; else if (dirname[dirlen - 1] == ':') { - /* DIRNAME is "d:". Use `:' instead of `/'. */ + /* DIRNAME is "d:". Use ':' instead of '/'. */ --dirlen; - sep_char = ':'; + dirsep_char = ':'; } } #endif @@ -1364,7 +1370,7 @@ prefix_array (const char *dirname, char **array, size_t n) for (i = 0; i < n; ++i) { size_t eltlen = strlen (array[i]) + 1; - char *new = (char *) malloc (dirlen + 1 + eltlen); + char *new = malloc (dirlen + 1 + eltlen); if (new == NULL) { while (i > 0) @@ -1374,7 +1380,7 @@ prefix_array (const char *dirname, char **array, size_t n) { char *endp = mempcpy (new, dirname, dirlen); - *endp++ = DIRSEP_CHAR; + *endp++ = dirsep_char; mempcpy (endp, array[i], eltlen); } free (array[i]); @@ -1384,103 +1390,57 @@ prefix_array (const char *dirname, char **array, size_t n) return 0; } - -/* We must not compile this function twice. */ -#if !defined _LIBC || !defined NO_GLOB_PATTERN_P -int -__glob_pattern_type (const char *pattern, int quote) -{ - const char *p; - int ret = 0; - - for (p = pattern; *p != '\0'; ++p) - switch (*p) - { - case '?': - case '*': - return 1; - - case '\\': - if (quote) - { - if (p[1] != '\0') - ++p; - ret |= 2; - } - break; - - case '[': - ret |= 4; - break; - - case ']': - if (ret & 4) - return 1; - break; - } - - return ret; -} - -/* Return nonzero if PATTERN contains any metacharacters. - Metacharacters can be quoted with backslashes if QUOTE is nonzero. */ -int -__glob_pattern_p (const char *pattern, int quote) -{ - return __glob_pattern_type (pattern, quote) == 1; -} -# ifdef _LIBC -weak_alias (__glob_pattern_p, glob_pattern_p) -# endif -#endif - -#endif /* !GLOB_ONLY_P */ - - /* We put this in a separate function mainly to allow the memory allocated with alloca to be recycled. */ -#if !defined _LIBC || !defined GLOB_ONLY_P static int __attribute_noinline__ -link_exists2_p (const char *dir, size_t dirlen, const char *fname, - glob_t *pglob -# ifndef _LIBC - , int flags +link_stat (const char *dir, size_t dirlen, const char *fname, + glob_t *pglob +# if !defined _LIBC && !HAVE_FSTATAT + , int flags # endif - ) + ) { size_t fnamelen = strlen (fname); - char *fullname = (char *) __alloca (dirlen + 1 + fnamelen + 1); + char *fullname = __alloca (dirlen + 1 + fnamelen + 1); struct stat st; -# ifndef _LIBC - struct_stat64 st64; -# endif mempcpy (mempcpy (mempcpy (fullname, dir, dirlen), "/", 1), fname, fnamelen + 1); -# ifdef _LIBC - return (*pglob->gl_stat) (fullname, &st) == 0; -# else - return ((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0) - ? (*pglob->gl_stat) (fullname, &st) - : __stat64 (fullname, &st64)) == 0); +# if !defined _LIBC && !HAVE_FSTATAT + if (__builtin_expect ((flags & GLOB_ALTDIRFUNC) == 0, 1)) + { + struct_stat64 st64; + return __stat64 (fullname, &st64); + } # endif + return (*pglob->gl_stat) (fullname, &st); } -# ifdef _LIBC -# define link_exists_p(dfd, dirname, dirnamelen, fname, pglob, flags) \ - (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0) \ - ? link_exists2_p (dirname, dirnamelen, fname, pglob) \ - : ({ struct stat64 st64; \ - __fxstatat64 (_STAT_VER, dfd, fname, &st64, 0) == 0; })) + +/* Return true if DIR/FNAME exists. */ +static int +link_exists_p (int dfd, const char *dir, size_t dirlen, const char *fname, + glob_t *pglob, int flags) +{ + int status; +# if defined _LIBC || HAVE_FSTATAT + if (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)) + status = link_stat (dir, dirlen, fname, pglob); + else + { + /* dfd cannot be -1 here, because dirfd never returns -1 on + glibc, or on hosts that have fstatat. */ + struct_stat64 st64; + status = __fxstatat64 (_STAT_VER, dfd, fname, &st64, 0); + } # else -# define link_exists_p(dfd, dirname, dirnamelen, fname, pglob, flags) \ - link_exists2_p (dirname, dirnamelen, fname, pglob, flags) + status = link_stat (dir, dirlen, fname, pglob, flags); # endif -#endif - + return status == 0 || errno == EOVERFLOW; +} -/* Like `glob', but PATTERN is a final pathname component, +/* Like 'glob', but PATTERN is a final pathname component, and matches are searched for in DIRECTORY. The GLOB_NOSORT bit in FLAGS is ignored. No sorting is ever done. The GLOB_APPEND flag is assumed to be set (always appends). */ @@ -1491,25 +1451,25 @@ glob_in_dir (const char *pattern, const char *directory, int flags, { size_t dirlen = strlen (directory); void *stream = NULL; - struct globnames - { - struct globnames *next; - size_t count; - char *name[64]; - }; -#define INITIAL_COUNT sizeof (init_names.name) / sizeof (init_names.name[0]) - struct globnames init_names; - struct globnames *names = &init_names; - struct globnames *names_alloca = &init_names; +# define GLOBNAMES_MEMBERS(nnames) \ + struct globnames *next; size_t count; char *name[nnames]; + struct globnames { GLOBNAMES_MEMBERS (FLEXIBLE_ARRAY_MEMBER) }; + struct { GLOBNAMES_MEMBERS (64) } init_names_buf; + struct globnames *init_names = (struct globnames *) &init_names_buf; + struct globnames *names = init_names; + struct globnames *names_alloca = init_names; size_t nfound = 0; size_t cur = 0; int meta; int save; + int result; - alloca_used += sizeof (init_names); + alloca_used += sizeof init_names_buf; - init_names.next = NULL; - init_names.count = INITIAL_COUNT; + init_names->next = NULL; + init_names->count = ((sizeof init_names_buf + - offsetof (struct globnames, name)) + / sizeof init_names->name[0]); meta = __glob_pattern_type (pattern, !(flags & GLOB_NOESCAPE)); if (meta == 0 && (flags & (GLOB_NOCHECK|GLOB_NOMAGIC))) @@ -1529,14 +1489,16 @@ glob_in_dir (const char *pattern, const char *directory, int flags, struct_stat64 st64; } ust; size_t patlen = strlen (pattern); - int alloca_fullname = __libc_use_alloca (alloca_used - + dirlen + 1 + patlen + 1); + size_t fullsize; + bool alloca_fullname + = (! size_add_wrapv (dirlen + 1, patlen + 1, &fullsize) + && glob_use_alloca (alloca_used, fullsize)); char *fullname; if (alloca_fullname) - fullname = alloca_account (dirlen + 1 + patlen + 1, alloca_used); + fullname = alloca_account (fullsize, alloca_used); else { - fullname = malloc (dirlen + 1 + patlen + 1); + fullname = malloc (fullsize); if (fullname == NULL) return GLOB_NOSPACE; } @@ -1544,9 +1506,11 @@ glob_in_dir (const char *pattern, const char *directory, int flags, mempcpy (mempcpy (mempcpy (fullname, directory, dirlen), "/", 1), pattern, patlen + 1); - if ((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0) + if (((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0) ? (*pglob->gl_stat) (fullname, &ust.st) - : __stat64 (fullname, &ust.st64)) == 0) + : __stat64 (fullname, &ust.st64)) + == 0) + || errno == EOVERFLOW) /* We found this file to be existing. Now tell the rest of the function to copy this name into the result. */ flags |= GLOB_NOCHECK; @@ -1568,16 +1532,10 @@ glob_in_dir (const char *pattern, const char *directory, int flags, } else { -#ifdef _LIBC int dfd = (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0) ? -1 : dirfd ((DIR *) stream)); -#endif int fnm_flags = ((!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0) - | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0) -#if defined _AMIGA || defined VMS - | FNM_CASEFOLD -#endif - ); + | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0)); flags |= GLOB_MAGCHAR; while (1) @@ -1597,19 +1555,24 @@ glob_in_dir (const char *pattern, const char *directory, int flags, } if (d.name == NULL) break; - if (d.skip_entry) + if (readdir_result_skip_entry (d)) continue; /* If we shall match only directories use the information provided by the dirent call if possible. */ - if ((flags & GLOB_ONLYDIR) && !readdir_result_might_be_dir (d)) - continue; + if (flags & GLOB_ONLYDIR) + switch (readdir_result_type (d)) + { + case DT_DIR: case DT_LNK: case DT_UNKNOWN: break; + default: continue; + } if (fnmatch (pattern, d.name, fnm_flags) == 0) { /* If the file we found is a symlink we have to make sure the target file exists. */ - if (!readdir_result_might_be_symlink (d) + dirent_type type = readdir_result_type (d); + if (! (type == DT_LNK || type == DT_UNKNOWN) || link_exists_p (dfd, directory, dirlen, d.name, pglob, flags)) { @@ -1617,10 +1580,13 @@ glob_in_dir (const char *pattern, const char *directory, int flags, { struct globnames *newnames; size_t count = names->count * 2; - size_t size = (sizeof (struct globnames) - + ((count - INITIAL_COUNT) - * sizeof (char *))); - if (__libc_use_alloca (alloca_used + size)) + size_t nameoff = offsetof (struct globnames, name); + size_t size = FLEXSIZEOF (struct globnames, name, + count * sizeof (char *)); + if ((SIZE_MAX - nameoff) / 2 / sizeof (char *) + < names->count) + goto memory_error; + if (glob_use_alloca (alloca_used, size)) newnames = names_alloca = alloca_account (size, alloca_used); else if ((newnames = malloc (size)) @@ -1636,6 +1602,8 @@ glob_in_dir (const char *pattern, const char *directory, int flags, goto memory_error; ++cur; ++nfound; + if (SIZE_MAX - pglob->gl_offs <= nfound) + goto memory_error; } } } @@ -1646,29 +1614,27 @@ glob_in_dir (const char *pattern, const char *directory, int flags, { size_t len = strlen (pattern); nfound = 1; - names->name[cur] = (char *) malloc (len + 1); + names->name[cur] = malloc (len + 1); if (names->name[cur] == NULL) goto memory_error; *((char *) mempcpy (names->name[cur++], pattern, len)) = '\0'; } - int result = GLOB_NOMATCH; + result = GLOB_NOMATCH; if (nfound != 0) { + char **new_gl_pathv; result = 0; - if (pglob->gl_pathc > UINTPTR_MAX - pglob->gl_offs - || pglob->gl_pathc + pglob->gl_offs > UINTPTR_MAX - nfound - || pglob->gl_pathc + pglob->gl_offs + nfound > UINTPTR_MAX - 1 - || (pglob->gl_pathc + pglob->gl_offs + nfound + 1 - > UINTPTR_MAX / sizeof (char *))) + if (SIZE_MAX / sizeof (char *) - pglob->gl_pathc + < pglob->gl_offs + nfound + 1) goto memory_error; - char **new_gl_pathv; new_gl_pathv - = (char **) realloc (pglob->gl_pathv, - (pglob->gl_pathc + pglob->gl_offs + nfound + 1) - * sizeof (char *)); + = realloc (pglob->gl_pathv, + (pglob->gl_pathc + pglob->gl_offs + nfound + 1) + * sizeof (char *)); + if (new_gl_pathv == NULL) { memory_error: @@ -1684,7 +1650,7 @@ glob_in_dir (const char *pattern, const char *directory, int flags, and this is the block assigned to OLD here. */ if (names == NULL) { - assert (old == &init_names); + assert (old == init_names); break; } cur = names->count; @@ -1710,7 +1676,7 @@ glob_in_dir (const char *pattern, const char *directory, int flags, and this is the block assigned to OLD here. */ if (names == NULL) { - assert (old == &init_names); + assert (old == init_names); break; } cur = names->count; diff --git a/posix/glob64.c b/posix/glob64.c index a5f5a7f9e2..39e54afe8b 100644 --- a/posix/glob64.c +++ b/posix/glob64.c @@ -43,10 +43,4 @@ glob64 (const char *pattern, int flags, } libc_hidden_def (glob64) -void -globfree64 (glob64_t *pglob) -{ -} -libc_hidden_def (globfree64) - stub_warning (glob64) diff --git a/posix/glob_internal.h b/posix/glob_internal.h new file mode 100644 index 0000000000..12c93660b7 --- /dev/null +++ b/posix/glob_internal.h @@ -0,0 +1,57 @@ +/* Shared definition for glob and glob_pattern_p. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef GLOB_INTERNAL_H +# define GLOB_INTERNAL_H + +static inline int +__glob_pattern_type (const char *pattern, int quote) +{ + const char *p; + int ret = 0; + + for (p = pattern; *p != '\0'; ++p) + switch (*p) + { + case '?': + case '*': + return 1; + + case '\\': + if (quote) + { + if (p[1] != '\0') + ++p; + ret |= 2; + } + break; + + case '[': + ret |= 4; + break; + + case ']': + if (ret & 4) + return 1; + break; + } + + return ret; +} + +#endif /* GLOB_INTERNAL_H */ diff --git a/posix/glob_pattern_p.c b/posix/glob_pattern_p.c new file mode 100644 index 0000000000..a17d337182 --- /dev/null +++ b/posix/glob_pattern_p.c @@ -0,0 +1,33 @@ +/* Return nonzero if PATTERN contains any metacharacters. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef _LIBC +# include +#endif + +#include +#include "glob_internal.h" + +/* Return nonzero if PATTERN contains any metacharacters. + Metacharacters can be quoted with backslashes if QUOTE is nonzero. */ +int +__glob_pattern_p (const char *pattern, int quote) +{ + return __glob_pattern_type (pattern, quote) == 1; +} +weak_alias (__glob_pattern_p, glob_pattern_p) diff --git a/posix/globfree.c b/posix/globfree.c new file mode 100644 index 0000000000..042e29d9b0 --- /dev/null +++ b/posix/globfree.c @@ -0,0 +1,41 @@ +/* Frees the dynamically allocated storage from an earlier call to glob. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef _LIBC +# include +#endif + +#include +#include + +/* Free storage allocated in PGLOB by a previous `glob' call. */ +void +globfree (glob_t *pglob) +{ + if (pglob->gl_pathv != NULL) + { + size_t i; + for (i = 0; i < pglob->gl_pathc; ++i) + free (pglob->gl_pathv[pglob->gl_offs + i]); + free (pglob->gl_pathv); + pglob->gl_pathv = NULL; + } +} +#ifndef globfree +libc_hidden_def (globfree) +#endif diff --git a/sysdeps/unix/sysv/linux/sh/pread.c b/posix/globfree64.c similarity index 68% rename from sysdeps/unix/sysv/linux/sh/pread.c rename to posix/globfree64.c index d3f99f35db..c9f8908a4e 100644 --- a/sysdeps/unix/sysv/linux/sh/pread.c +++ b/posix/globfree64.c @@ -1,6 +1,6 @@ -/* Copyright (C) 1997-2016 Free Software Foundation, Inc. +/* Frees the dynamically allocated storage from an earlier call to glob. + Copyright (C) 2017 Free Software Foundation, Inc. This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1997. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -16,8 +16,16 @@ License along with the GNU C Library; if not, see . */ -/* SH4 ABI does not really require argument alignment for 64-bits, but - the kernel interface for pread adds a dummy long argument before the - offset. */ -#define __ALIGNMENT_ARG -#include +#ifndef _LIBC +# include +#endif + +#include +#include + +/* Free storage allocated in PGLOB by a previous `glob' call. */ +void +globfree64 (glob64_t *pglob) +{ +} +libc_hidden_def (globfree64) diff --git a/posix/tst-glob-tilde.c b/posix/tst-glob-tilde.c new file mode 100644 index 0000000000..6886f4371f --- /dev/null +++ b/posix/tst-glob-tilde.c @@ -0,0 +1,143 @@ +/* Check for GLOB_TIDLE heap allocation issues (bugs 22320, 22325, 22332). + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Flag which indicates whether to pass the GLOB_ONLYDIR flag. */ +static int do_onlydir; + +/* Flag which indicates whether to pass the GLOB_NOCHECK flag. */ +static int do_nocheck; + +/* Flag which indicates whether to pass the GLOB_MARK flag. */ +static int do_mark; + +/* Flag which indicates whether to pass the GLOB_NOESCAPE flag. */ +static int do_noescape; + +static void +one_test (const char *prefix, const char *middle, const char *suffix) +{ + char *pattern = xasprintf ("%s%s%s", prefix, middle, suffix); + int flags = GLOB_TILDE; + if (do_onlydir) + flags |= GLOB_ONLYDIR; + if (do_nocheck) + flags |= GLOB_NOCHECK; + if (do_mark) + flags |= GLOB_MARK; + if (do_noescape) + flags |= GLOB_NOESCAPE; + glob_t gl; + /* This glob call might result in crashes or memory leaks. */ + if (glob (pattern, flags, NULL, &gl) == 0) + globfree (&gl); + free (pattern); +} + +enum + { + /* The largest base being tested. */ + largest_base_size = 500000, + + /* The actual size is the base size plus a variable whose absolute + value is not greater than this. This helps malloc to trigger + overflows. */ + max_size_skew = 16, + + /* The maximum string length supported by repeating_string + below. */ + repeat_size = largest_base_size + max_size_skew, + }; + +/* Used to construct strings which repeat a single character 'x'. */ +static char *repeat; + +/* Return a string of SIZE characters. */ +const char * +repeating_string (int size) +{ + TEST_VERIFY (size >= 0); + TEST_VERIFY (size <= repeat_size); + const char *repeated_shifted = repeat + repeat_size - size; + TEST_VERIFY (strlen (repeated_shifted) == size); + return repeated_shifted; +} + +static int +do_test (void) +{ + /* Avoid network-based NSS modules and initialize nss_files with a + dummy lookup. This has to come before mtrace because NSS does + not free all memory. */ + __nss_configure_lookup ("passwd", "files"); + (void) getpwnam ("root"); + + mtrace (); + + repeat = xmalloc (repeat_size + 1); + memset (repeat, 'x', repeat_size); + repeat[repeat_size] = '\0'; + + /* These numbers control the size of the user name. The values + cover the minimum (0), a typical size (8), a large + stack-allocated size (100000), and a somewhat large + heap-allocated size (largest_base_size). */ + static const int base_sizes[] = { 0, 8, 100, 100000, largest_base_size, -1 }; + + for (do_onlydir = 0; do_onlydir < 2; ++do_onlydir) + for (do_nocheck = 0; do_nocheck < 2; ++do_nocheck) + for (do_mark = 0; do_mark < 2; ++do_mark) + for (do_noescape = 0; do_noescape < 2; ++do_noescape) + for (int base_idx = 0; base_sizes[base_idx] >= 0; ++base_idx) + { + for (int size_skew = -max_size_skew; size_skew <= max_size_skew; + ++size_skew) + { + int size = base_sizes[base_idx] + size_skew; + if (size < 0) + continue; + + const char *user_name = repeating_string (size); + one_test ("~", user_name, "/a/b"); + one_test ("~", user_name, "x\\x\\x////x\\a"); + } + + const char *user_name = repeating_string (base_sizes[base_idx]); + one_test ("~", user_name, ""); + one_test ("~", user_name, "/"); + one_test ("~", user_name, "/a"); + one_test ("~", user_name, "/*/*"); + one_test ("~", user_name, "\\/"); + one_test ("/~", user_name, ""); + one_test ("*/~", user_name, "/a/b"); + } + + free (repeat); + + return 0; +} + +#include diff --git a/resolv/Makefile b/resolv/Makefile index 8be41d3ae1..a4c86b9762 100644 --- a/resolv/Makefile +++ b/resolv/Makefile @@ -40,6 +40,9 @@ ifeq ($(have-thread-library),yes) extra-libs += libanl routines += gai_sigqueue tests += tst-res_hconf_reorder + +# This test sends millions of packets and is rather slow. +xtests += tst-resolv-qtypes endif extra-libs-others = $(extra-libs) libresolv-routines := gethnamaddr res_comp res_debug \ @@ -117,3 +120,5 @@ tst-leaks2-ENV = MALLOC_TRACE=$(objpfx)tst-leaks2.mtrace $(objpfx)mtrace-tst-leaks2.out: $(objpfx)tst-leaks2.out $(common-objpfx)malloc/mtrace $(objpfx)tst-leaks2.mtrace > $@; \ $(evaluate-test) + +$(objpfx)tst-resolv-qtypes: $(objpfx)libresolv.so $(shared-thread-library) diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c index 5f9e35701b..d16fa4b8ed 100644 --- a/resolv/nss_dns/dns-host.c +++ b/resolv/nss_dns/dns-host.c @@ -323,7 +323,7 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, int olderr = errno; enum nss_status status; - int n = __libc_res_nsearch (&_res, name, C_IN, T_UNSPEC, + int n = __libc_res_nsearch (&_res, name, C_IN, T_QUERY_A_AND_AAAA, host_buffer.buf->buf, 2048, &host_buffer.ptr, &ans2p, &nans2p, &resplen2, &ans2p_malloced); if (n >= 0) diff --git a/resolv/res_mkquery.c b/resolv/res_mkquery.c index 12f9730199..d80b5318e5 100644 --- a/resolv/res_mkquery.c +++ b/resolv/res_mkquery.c @@ -103,6 +103,10 @@ res_nmkquery(res_state statp, int n; u_char *dnptrs[20], **dpp, **lastdnptr; + if (class < 0 || class > 65535 + || type < 0 || type > 65535) + return -1; + #ifdef DEBUG if (statp->options & RES_DEBUG) printf(";; res_nmkquery(%s, %s, %s, %s)\n", diff --git a/resolv/res_query.c b/resolv/res_query.c index 944d1a90f5..07dc6f6583 100644 --- a/resolv/res_query.c +++ b/resolv/res_query.c @@ -122,7 +122,7 @@ __libc_res_nquery(res_state statp, int n, use_malloc = 0; u_int oflags = statp->_flags; - size_t bufsize = (type == T_UNSPEC ? 2 : 1) * QUERYSIZE; + size_t bufsize = (type == T_QUERY_A_AND_AAAA ? 2 : 1) * QUERYSIZE; u_char *buf = alloca (bufsize); u_char *query1 = buf; int nquery1 = -1; @@ -137,7 +137,7 @@ __libc_res_nquery(res_state statp, printf(";; res_query(%s, %d, %d)\n", name, class, type); #endif - if (type == T_UNSPEC) + if (type == T_QUERY_A_AND_AAAA) { n = res_nmkquery(statp, QUERY, name, class, T_A, NULL, 0, NULL, query1, bufsize); @@ -190,7 +190,7 @@ __libc_res_nquery(res_state statp, if (__builtin_expect (n <= 0, 0) && !use_malloc) { /* Retry just in case res_nmkquery failed because of too short buffer. Shouldn't happen. */ - bufsize = (type == T_UNSPEC ? 2 : 1) * MAXPACKET; + bufsize = (type == T_QUERY_A_AND_AAAA ? 2 : 1) * MAXPACKET; buf = malloc (bufsize); if (buf != NULL) { query1 = buf; diff --git a/resolv/tst-resolv-qtypes.c b/resolv/tst-resolv-qtypes.c new file mode 100644 index 0000000000..b3e60c693b --- /dev/null +++ b/resolv/tst-resolv-qtypes.c @@ -0,0 +1,185 @@ +/* Exercise low-level query functions with different QTYPEs. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* If ture, the response function will send the actual response packet + over TCP instead of UDP. */ +static volatile bool force_tcp; + +/* Send back a fake resource record matching the QTYPE. */ +static void +response (const struct resolv_response_context *ctx, + struct resolv_response_builder *b, + const char *qname, uint16_t qclass, uint16_t qtype) +{ + if (force_tcp && ctx->tcp) + { + resolv_response_init (b, (struct resolv_response_flags) { .tc = 1 }); + resolv_response_add_question (b, qname, qclass, qtype); + return; + } + + resolv_response_init (b, (struct resolv_response_flags) { }); + resolv_response_add_question (b, qname, qclass, qtype); + resolv_response_section (b, ns_s_an); + resolv_response_open_record (b, qname, qclass, qtype, 0); + resolv_response_add_data (b, &qtype, sizeof (qtype)); + resolv_response_close_record (b); +} + +static const const char *domain = "www.example.com"; + +static int +wrap_res_query (int type, unsigned char *answer, int answer_length) +{ + return res_query (domain, C_IN, type, answer, answer_length); +} + +static int +wrap_res_search (int type, unsigned char *answer, int answer_length) +{ + return res_query (domain, C_IN, type, answer, answer_length); +} + +static int +wrap_res_querydomain (int type, unsigned char *answer, int answer_length) +{ + return res_querydomain ("www", "example.com", C_IN, type, + answer, answer_length); +} + +static int +wrap_res_send (int type, unsigned char *answer, int answer_length) +{ + unsigned char buf[512]; + int ret = res_mkquery (QUERY, domain, C_IN, type, + (const unsigned char *) "", 0, NULL, + buf, sizeof (buf)); + if (type < 0 || type >= 65536) + { + /* res_mkquery fails for out-of-range record types. */ + TEST_VERIFY_EXIT (ret == -1); + return -1; + } + TEST_VERIFY_EXIT (ret > 12); /* DNS header length. */ + return res_send (buf, ret, answer, answer_length); +} + +static int +wrap_res_nquery (int type, unsigned char *answer, int answer_length) +{ + return res_nquery (&_res, domain, C_IN, type, answer, answer_length); +} + +static int +wrap_res_nsearch (int type, unsigned char *answer, int answer_length) +{ + return res_nquery (&_res, domain, C_IN, type, answer, answer_length); +} + +static int +wrap_res_nquerydomain (int type, unsigned char *answer, int answer_length) +{ + return res_nquerydomain (&_res, "www", "example.com", C_IN, type, + answer, answer_length); +} + +static int +wrap_res_nsend (int type, unsigned char *answer, int answer_length) +{ + unsigned char buf[512]; + int ret = res_nmkquery (&_res, QUERY, domain, C_IN, type, + (const unsigned char *) "", 0, NULL, + buf, sizeof (buf)); + if (type < 0 || type >= 65536) + { + /* res_mkquery fails for out-of-range record types. */ + TEST_VERIFY_EXIT (ret == -1); + return -1; + } + TEST_VERIFY_EXIT (ret > 12); /* DNS header length. */ + return res_nsend (&_res, buf, ret, answer, answer_length); +} + +static void +test_function (const char *fname, + int (*func) (int type, + unsigned char *answer, int answer_length)) +{ + unsigned char buf[512]; + for (int tcp = 0; tcp < 2; ++tcp) + { + force_tcp = tcp; + for (unsigned int type = 1; type <= 65535; ++type) + { + if (test_verbose) + printf ("info: sending QTYPE %d with %s (tcp=%d)\n", + type, fname, tcp); + int ret = func (type, buf, sizeof (buf)); + if (ret != 47) + FAIL_EXIT1 ("%s tcp=%d qtype=%d return value %d", + fname,tcp, type, ret); + /* One question, one answer record. */ + TEST_VERIFY (memcmp (buf + 4, "\0\1\0\1\0\0\0\0", 8) == 0); + /* Question section. */ + static const char qname[] = "\3www\7example\3com"; + size_t qname_length = sizeof (qname); + TEST_VERIFY (memcmp (buf + 12, qname, qname_length) == 0); + /* RDATA part of answer. */ + uint16_t type16 = type; + TEST_VERIFY (memcmp (buf + ret - 2, &type16, sizeof (type16)) == 0); + } + } + + TEST_VERIFY (func (-1, buf, sizeof (buf) == -1)); + TEST_VERIFY (func (65536, buf, sizeof (buf) == -1)); +} + +static int +do_test (void) +{ + struct resolv_redirect_config config = + { + .response_callback = response, + }; + struct resolv_test *obj = resolv_test_start (config); + + test_function ("res_query", &wrap_res_query); + test_function ("res_search", &wrap_res_search); + test_function ("res_querydomain", &wrap_res_querydomain); + test_function ("res_send", &wrap_res_send); + + test_function ("res_nquery", &wrap_res_nquery); + test_function ("res_nsearch", &wrap_res_nsearch); + test_function ("res_nquerydomain", &wrap_res_nquerydomain); + test_function ("res_nsend", &wrap_res_nsend); + + resolv_test_end (obj); + return 0; +} + +#define TIMEOUT 300 +#include diff --git a/scripts/backport-support.sh b/scripts/backport-support.sh new file mode 100644 index 0000000000..2ece7ce575 --- /dev/null +++ b/scripts/backport-support.sh @@ -0,0 +1,110 @@ +#!/bin/bash +# Create a patch which backports the support/ subdirectory. +# Copyright (C) 2017 Free Software Foundation, Inc. +# This file is part of the GNU C Library. + +# The GNU C Library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. + +# The GNU C Library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. + +# You should have received a copy of the GNU Lesser General Public +# License along with the GNU C Library; if not, see +# . + +# This script does not backport the Makefile tweaks outside the +# support/ directory (which need to be backported separately), or the +# changes to test-skeleton.c (which should not be backported). + +set -e + +export LC_ALL=C +export GIT_CONFIG=/dev/null +export GTT_CONFIG_NOSYSTEM=0 +export GIT_PAGER= + +usage () { + cat >&2 <&2 + echo "# rm -rf $patch_targets" >&2 +} + +command_commit () { + git status --porcelain | while read line ; do + echo "error: working copy is not clean, cannot commit" >&2 + exit 1 + done + for path in $patch_targets; do + echo "# Processing $path" >&2 + case "$path" in + [a-zA-Z0-9]*/) + # Directory. + git rm --cached --ignore-unmatch -r "$path" + rm -rf "$path" + git read-tree --prefix="$path" "$latest_commit":"$path" + git checkout "$path" + ;; + *) + # File. + git show "$latest_commit":"$path" > "$path" + git add "$path" + esac + done + git commit -m "Synchronize support/ infrastructure with $branch_name + +This commit updates the support/ subdirectory to +commit $latest_commit +on the $branch_name branch. +" +} + +command_$command diff --git a/sunrpc/Makefile b/sunrpc/Makefile index 789ef423e5..1e91905011 100644 --- a/sunrpc/Makefile +++ b/sunrpc/Makefile @@ -96,13 +96,18 @@ rpcgen-objs = rpc_main.o rpc_hout.o rpc_cout.o rpc_parse.o \ extra-objs = $(rpcgen-objs) $(addprefix cross-,$(rpcgen-objs)) others += rpcgen -tests = tst-xdrmem tst-xdrmem2 test-rpcent +tests = tst-xdrmem tst-xdrmem2 test-rpcent tst-udp-error xtests := tst-getmyaddr ifeq ($(have-thread-library),yes) xtests += thrsvc endif +ifeq ($(run-built-tests),yes) +rpcgen-tests := $(objpfx)bug20790.out +tests-special += $(rpcgen-tests) +endif + headers += $(rpcsvc:%.x=rpcsvc/%.h) extra-libs := librpcsvc extra-libs-others := librpcsvc # Make it in `others' pass, not `lib' pass. @@ -153,6 +158,7 @@ BUILD_CPPFLAGS += $(sunrpc-CPPFLAGS) $(objpfx)tst-getmyaddr: $(common-objpfx)linkobj/libc.so $(objpfx)tst-xdrmem: $(common-objpfx)linkobj/libc.so $(objpfx)tst-xdrmem2: $(common-objpfx)linkobj/libc.so +$(objpfx)tst-udp-error: $(common-objpfx)linkobj/libc.so $(objpfx)rpcgen: $(addprefix $(objpfx),$(rpcgen-objs)) @@ -225,3 +231,9 @@ endif endif $(objpfx)thrsvc: $(common-objpfx)linkobj/libc.so $(shared-thread-library) + +ifeq ($(run-built-tests),yes) +$(rpcgen-tests): $(objpfx)%.out: %.x $(objpfx)rpcgen + $(built-program-cmd) -c $< -o $@; \ + $(evaluate-test) +endif diff --git a/sunrpc/bug20790.x b/sunrpc/bug20790.x new file mode 100644 index 0000000000..a00c9b3830 --- /dev/null +++ b/sunrpc/bug20790.x @@ -0,0 +1 @@ +program TPROG { version TVERS { int FUNC(int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) = 1; } = 1; } = 1; diff --git a/sunrpc/clnt_udp.c b/sunrpc/clnt_udp.c index 4d9acb1e6a..1de25cb771 100644 --- a/sunrpc/clnt_udp.c +++ b/sunrpc/clnt_udp.c @@ -421,9 +421,9 @@ send_again: cmsg = CMSG_NXTHDR (&msg, cmsg)) if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR) { - free (cbuf); e = (struct sock_extended_err *) CMSG_DATA(cmsg); cu->cu_error.re_errno = e->ee_errno; + free (cbuf); return (cu->cu_error.re_status = RPC_CANTRECV); } free (cbuf); diff --git a/sunrpc/rpc_parse.c b/sunrpc/rpc_parse.c index 1a1df6d8c2..505a6554cf 100644 --- a/sunrpc/rpc_parse.c +++ b/sunrpc/rpc_parse.c @@ -521,7 +521,7 @@ static void get_prog_declaration (declaration * dec, defkind dkind, int num /* arg number */ ) { token tok; - char name[10]; /* argument name */ + char name[MAXLINESIZE]; /* argument name */ if (dkind == DEF_PROGRAM) { diff --git a/sunrpc/tst-udp-error.c b/sunrpc/tst-udp-error.c new file mode 100644 index 0000000000..1efc02f5c6 --- /dev/null +++ b/sunrpc/tst-udp-error.c @@ -0,0 +1,62 @@ +/* Check for use-after-free in clntudp_call (bug 21115). + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include +#include + +static int +do_test (void) +{ + support_become_root (); + support_enter_network_namespace (); + + /* Obtain a likely-unused port number. */ + struct sockaddr_in sin = + { + .sin_family = AF_INET, + .sin_addr.s_addr = htonl (INADDR_LOOPBACK), + }; + { + int fd = xsocket (AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); + xbind (fd, (struct sockaddr *) &sin, sizeof (sin)); + socklen_t sinlen = sizeof (sin); + xgetsockname (fd, (struct sockaddr *) &sin, &sinlen); + /* Close the socket, so that we will receive an error below. */ + close (fd); + } + + int sock = RPC_ANYSOCK; + CLIENT *clnt = clntudp_create + (&sin, 1, 2, (struct timeval) { 1, 0 }, &sock); + TEST_VERIFY_EXIT (clnt != NULL); + TEST_VERIFY (clnt_call (clnt, 3, + (xdrproc_t) xdr_void, NULL, + (xdrproc_t) xdr_void, NULL, + ((struct timeval) { 3, 0 })) + == RPC_CANTRECV); + clnt_destroy (clnt); + + return 0; +} + +#include diff --git a/support/Makefile b/support/Makefile new file mode 100644 index 0000000000..20b0343ade --- /dev/null +++ b/support/Makefile @@ -0,0 +1,146 @@ +# Makefile for support library, used only at build and test time +# Copyright (C) 2016-2017 Free Software Foundation, Inc. +# This file is part of the GNU C Library. + +# The GNU C Library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. + +# The GNU C Library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. + +# You should have received a copy of the GNU Lesser General Public +# License along with the GNU C Library; if not, see +# . + +subdir := support + +include ../Makeconfig + +extra-libs := libsupport +extra-libs-others = $(extra-libs) +extra-libs-noinstall := $(extra-libs) + +libsupport-routines = \ + check \ + check_addrinfo \ + check_dns_packet \ + check_hostent \ + check_netent \ + delayed_exit \ + ignore_stderr \ + oom_error \ + resolv_test \ + set_fortify_handler \ + support-xstat \ + support_become_root \ + support_can_chroot \ + support_capture_subprocess \ + support_capture_subprocess_check \ + support_enter_network_namespace \ + support_format_address_family \ + support_format_addrinfo \ + support_format_dns_packet \ + support_format_herrno \ + support_format_hostent \ + support_format_netent \ + support_isolate_in_subprocess \ + support_record_failure \ + support_run_diff \ + support_shared_allocate \ + support_write_file_string \ + support_test_main \ + support_test_verify_impl \ + temp_file \ + write_message \ + xaccept \ + xaccept4 \ + xasprintf \ + xbind \ + xcalloc \ + xchroot \ + xclose \ + xconnect \ + xdup2 \ + xfclose \ + xfopen \ + xfork \ + xgetsockname \ + xlisten \ + xmalloc \ + xmemstream \ + xmkdir \ + xmmap \ + xmunmap \ + xopen \ + xpipe \ + xpoll \ + xpthread_attr_destroy \ + xpthread_attr_init \ + xpthread_attr_setdetachstate \ + xpthread_attr_setstacksize \ + xpthread_barrier_destroy \ + xpthread_barrier_init \ + xpthread_barrier_wait \ + xpthread_cancel \ + xpthread_check_return \ + xpthread_cond_wait \ + xpthread_create \ + xpthread_detach \ + xpthread_join \ + xpthread_mutex_consistent \ + xpthread_mutex_destroy \ + xpthread_mutex_init \ + xpthread_mutex_lock \ + xpthread_mutex_unlock \ + xpthread_mutexattr_destroy \ + xpthread_mutexattr_init \ + xpthread_mutexattr_setprotocol \ + xpthread_mutexattr_setpshared \ + xpthread_mutexattr_setrobust \ + xpthread_mutexattr_settype \ + xpthread_once \ + xpthread_sigmask \ + xpthread_spin_lock \ + xpthread_spin_unlock \ + xrealloc \ + xrecvfrom \ + xsendto \ + xsetsockopt \ + xsocket \ + xstrdup \ + xwaitpid \ + xwrite \ + +libsupport-static-only-routines := $(libsupport-routines) +# Only build one variant of the library. +libsupport-inhibit-o := .os +ifeq ($(build-shared),yes) +libsupport-inhibit-o += .o +endif + +tests = \ + README-testing \ + tst-support-namespace \ + tst-support_capture_subprocess \ + tst-support_format_dns_packet \ + tst-support_record_failure \ + +ifeq ($(run-built-tests),yes) +tests-special = \ + $(objpfx)tst-support_record_failure-2.out + +$(objpfx)tst-support_record_failure-2.out: tst-support_record_failure-2.sh \ + $(objpfx)tst-support_record_failure + $(SHELL) $< $(common-objpfx) '$(test-program-prefix-before-env)' \ + '$(run-program-env)' '$(test-program-prefix-after-env)' \ + > $@; \ + $(evaluate-test) +endif + +$(objpfx)tst-support_format_dns_packet: $(common-objpfx)resolv/libresolv.so + +include ../Rules diff --git a/support/README b/support/README new file mode 100644 index 0000000000..476cfcda59 --- /dev/null +++ b/support/README @@ -0,0 +1,29 @@ +This subdirectory contains infrastructure which is not put into +installed libraries, but may be linked into programs (installed or +not) and tests. + +# Error-checking wrappers + +These wrappers test for error return codes an terminate the process on +error. They are declared in these header files: + +* support.h +* xsignal.h +* xthread.h + +In general, new wrappers should be added to support.h if possible. +However, support.h must remain fully compatible with C90 and therefore +cannot include headers which use identifers not reserved in C90. If +the wrappers need additional types, additional headers such as +signal.h need to be introduced. + +# Test framework + +The test framework provides a main program for tests, including a +timeout for hanging tests. See README-testing.c for a minimal +example, and test-driver.c for details how to use it. The following +header files provide related declarations: + +* check.h +* temp_file.h +* test-driver.h diff --git a/support/README-testing.c b/support/README-testing.c new file mode 100644 index 0000000000..9d289c3020 --- /dev/null +++ b/support/README-testing.c @@ -0,0 +1,19 @@ +/* This file contains an example test case which shows minimal use of + the test framework. Additional testing hooks are described in + . */ + +/* This function will be called from the test driver. */ +static int +do_test (void) +{ + if (3 == 5) + /* Indicate failure. */ + return 1; + else + /* Indicate success. */ + return 0; +} + +/* This file references do_test above and contains the definition of + the main function. */ +#include diff --git a/support/capture_subprocess.h b/support/capture_subprocess.h new file mode 100644 index 0000000000..43caf9bce4 --- /dev/null +++ b/support/capture_subprocess.h @@ -0,0 +1,61 @@ +/* Capture output from a subprocess. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef SUPPORT_CAPTURE_SUBPROCESS_H +#define SUPPORT_CAPTURE_SUBPROCESS_H + +#include + +struct support_capture_subprocess +{ + struct xmemstream out; + struct xmemstream err; + int status; +}; + +/* Invoke CALLBACK (CLOSURE) in a subprocess and capture standard + output, standard error, and the exit status. The out.buffer and + err.buffer members in the result are null-terminated strings which + can be examined by the caller (out.out and err.out are NULL). */ +struct support_capture_subprocess support_capture_subprocess + (void (*callback) (void *), void *closure); + +/* Deallocate the subprocess data captured by + support_capture_subprocess. */ +void support_capture_subprocess_free (struct support_capture_subprocess *); + +enum support_capture_allow +{ + /* No output is allowed. */ + sc_allow_none = 0x01, + /* Output to stdout is permitted. */ + sc_allow_stdout = 0x02, + /* Output to standard error is permitted. */ + sc_allow_stderr = 0x04, +}; + +/* Check that the subprocess exited with STATUS and that only the + allowed outputs happened. ALLOWED is a combination of + support_capture_allow flags. Report errors under the CONTEXT + message. */ +void support_capture_subprocess_check (struct support_capture_subprocess *, + const char *context, int status, + int allowed) + __attribute__ ((nonnull (1, 2))); + +#endif /* SUPPORT_CAPTURE_SUBPROCESS_H */ diff --git a/support/check.c b/support/check.c new file mode 100644 index 0000000000..592f2bc856 --- /dev/null +++ b/support/check.c @@ -0,0 +1,57 @@ +/* Support code for reporting test results. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include +#include + +static void +print_failure (const char *file, int line, const char *format, va_list ap) +{ + printf ("error: %s:%d: ", file, line); + vprintf (format, ap); + puts (""); +} + +int +support_print_failure_impl (const char *file, int line, + const char *format, ...) +{ + support_record_failure (); + va_list ap; + va_start (ap, format); + print_failure (file, line, format, ap); + va_end (ap); + return 1; +} + +void +support_exit_failure_impl (int status, const char *file, int line, + const char *format, ...) +{ + if (status != EXIT_SUCCESS && status != EXIT_UNSUPPORTED) + support_record_failure (); + va_list ap; + va_start (ap, format); + print_failure (file, line, format, ap); + va_end (ap); + exit (status); +} diff --git a/support/check.h b/support/check.h new file mode 100644 index 0000000000..1d244a3557 --- /dev/null +++ b/support/check.h @@ -0,0 +1,94 @@ +/* Functionality for reporting test results. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef SUPPORT_CHECK_H +#define SUPPORT_CHECK_H + +#include + +__BEGIN_DECLS + +/* Record a test failure, print the failure message to standard output + and return 1. */ +#define FAIL_RET(...) \ + return support_print_failure_impl (__FILE__, __LINE__, __VA_ARGS__) + +/* Print the failure message and terminate the process with STATUS. + Record a the process as failed if STATUS is neither EXIT_SUCCESS + nor EXIT_UNSUPPORTED. */ +#define FAIL_EXIT(status, ...) \ + support_exit_failure_impl (status, __FILE__, __LINE__, __VA_ARGS__) + +/* Record a test failure, print the failure message and terminate with + exit status 1. */ +#define FAIL_EXIT1(...) \ + support_exit_failure_impl (1, __FILE__, __LINE__, __VA_ARGS__) + +/* Print failure message and terminate with as unsupported test (exit + status of 77). */ +#define FAIL_UNSUPPORTED(...) \ + support_exit_failure_impl (77, __FILE__, __LINE__, __VA_ARGS__) + +/* Record a test failure (but continue executing) if EXPR evaluates to + false. */ +#define TEST_VERIFY(expr) \ + ({ \ + if (expr) \ + ; \ + else \ + support_test_verify_impl (-1, __FILE__, __LINE__, #expr); \ + }) + +/* Record a test failure and exit if EXPR evaluates to false. */ +#define TEST_VERIFY_EXIT(expr) \ + ({ \ + if (expr) \ + ; \ + else \ + support_test_verify_impl (1, __FILE__, __LINE__, #expr); \ + }) + +int support_print_failure_impl (const char *file, int line, + const char *format, ...) + __attribute__ ((nonnull (1), format (printf, 3, 4))); +void support_exit_failure_impl (int exit_status, + const char *file, int line, + const char *format, ...) + __attribute__ ((noreturn, nonnull (2), format (printf, 4, 5))); +void support_test_verify_impl (int status, const char *file, int line, + const char *expr); + +/* Record a test failure. This function returns and does not + terminate the process. The failure counter is stored in a shared + memory mapping, so that failures reported in child processes are + visible to the parent process and test driver. This function + depends on initialization by an ELF constructor, so it can only be + invoked after the test driver has run. Note that this function + does not support reporting failures from a DSO. */ +void support_record_failure (void); + +/* Internal function called by the test driver. */ +int support_report_failure (int status) + __attribute__ ((weak, warn_unused_result)); + +/* Internal function used to test the failure recording framework. */ +void support_record_failure_reset (void); + +__END_DECLS + +#endif /* SUPPORT_CHECK_H */ diff --git a/support/check_addrinfo.c b/support/check_addrinfo.c new file mode 100644 index 0000000000..55895ace3c --- /dev/null +++ b/support/check_addrinfo.c @@ -0,0 +1,42 @@ +/* Compare struct addrinfo values against a formatted string. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include +#include +#include + +void +check_addrinfo (const char *query_description, struct addrinfo *ai, int ret, + const char *expected) +{ + char *formatted = support_format_addrinfo (ai, ret); + if (strcmp (formatted, expected) != 0) + { + support_record_failure (); + printf ("error: addrinfo comparison failure\n"); + if (query_description != NULL) + printf ("query: %s\n", query_description); + support_run_diff ("expected", expected, + "actual", formatted); + } + free (formatted); +} diff --git a/support/check_dns_packet.c b/support/check_dns_packet.c new file mode 100644 index 0000000000..d2a31bed7b --- /dev/null +++ b/support/check_dns_packet.c @@ -0,0 +1,42 @@ +/* Check that a DNS packet buffer has the expected contents. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include +#include +#include + +void +check_dns_packet (const char *query_description, + const unsigned char *buffer, size_t length, + const char *expected) +{ + char *formatted = support_format_dns_packet (buffer, length); + if (strcmp (formatted, expected) != 0) + { + support_record_failure (); + printf ("error: packet comparison failure\n"); + if (query_description != NULL) + printf ("query: %s\n", query_description); + support_run_diff ("expected", expected, "actual", formatted); + } + free (formatted); +} diff --git a/support/check_hostent.c b/support/check_hostent.c new file mode 100644 index 0000000000..890d672d50 --- /dev/null +++ b/support/check_hostent.c @@ -0,0 +1,42 @@ +/* Compare struct hostent values against a formatted string. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include +#include +#include + +void +check_hostent (const char *query_description, struct hostent *h, + const char *expected) +{ + char *formatted = support_format_hostent (h); + if (strcmp (formatted, expected) != 0) + { + support_record_failure (); + printf ("error: hostent comparison failure\n"); + if (query_description != NULL) + printf ("query: %s\n", query_description); + support_run_diff ("expected", expected, + "actual", formatted); + } + free (formatted); +} diff --git a/support/check_netent.c b/support/check_netent.c new file mode 100644 index 0000000000..daa3083fd1 --- /dev/null +++ b/support/check_netent.c @@ -0,0 +1,42 @@ +/* Compare struct netent values against a formatted string. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include +#include +#include + +void +check_netent (const char *query_description, struct netent *e, + const char *expected) +{ + char *formatted = support_format_netent (e); + if (strcmp (formatted, expected) != 0) + { + support_record_failure (); + printf ("error: netent comparison failure\n"); + if (query_description != NULL) + printf ("query: %s\n", query_description); + support_run_diff ("expected", expected, + "actual", formatted); + } + free (formatted); +} diff --git a/support/check_nss.h b/support/check_nss.h new file mode 100644 index 0000000000..2893f2c295 --- /dev/null +++ b/support/check_nss.h @@ -0,0 +1,42 @@ +/* Test verification functions for NSS- and DNS-related data. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef SUPPORT_CHECK_NSS_H +#define SUPPORT_CHECK_NSS_H + +#include +#include + +__BEGIN_DECLS + +/* Compare the data structures against the expected values (which have + to be formatted according to the support_format_* functions in + ). If there is a difference, a delayed test + failure is recorded, and a diff is written to standard output. */ +void check_addrinfo (const char *query_description, + struct addrinfo *, int ret, const char *expected); +void check_dns_packet (const char *query_description, + const unsigned char *, size_t, const char *expected); +void check_hostent (const char *query_description, + struct hostent *, const char *expected); +void check_netent (const char *query_description, + struct netent *, const char *expected); + +__END_DECLS + +#endif /* SUPPORT_CHECK_NSS_H */ diff --git a/support/delayed_exit.c b/support/delayed_exit.c new file mode 100644 index 0000000000..67442f95df --- /dev/null +++ b/support/delayed_exit.c @@ -0,0 +1,55 @@ +/* Time-triggered process termination. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include + +#include +#include +#include +#include +#include + +static void * +delayed_exit_thread (void *seconds_as_ptr) +{ + int seconds = (uintptr_t) seconds_as_ptr; + struct timespec delay = { seconds, 0 }; + struct timespec remaining = { 0 }; + if (nanosleep (&delay, &remaining) != 0) + FAIL_EXIT1 ("nanosleep: %m"); + /* Exit the process sucessfully. */ + exit (0); + return NULL; +} + +void +delayed_exit (int seconds) +{ + /* Create the new thread with all signals blocked. */ + sigset_t all_blocked; + sigfillset (&all_blocked); + sigset_t old_set; + xpthread_sigmask (SIG_SETMASK, &all_blocked, &old_set); + /* Create a detached thread. */ + pthread_t thr = xpthread_create + (NULL, delayed_exit_thread, (void *) (uintptr_t) seconds); + xpthread_detach (thr); + /* Restore the original signal mask. */ + xpthread_sigmask (SIG_SETMASK, &old_set, NULL); +} diff --git a/support/format_nss.h b/support/format_nss.h new file mode 100644 index 0000000000..fb4597c238 --- /dev/null +++ b/support/format_nss.h @@ -0,0 +1,41 @@ +/* String formatting functions for NSS- and DNS-related data. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef SUPPORT_FORMAT_NSS_H +#define SUPPORT_FORMAT_NSS_H + +#include +#include + +__BEGIN_DECLS + +/* The following functions format their arguments as human-readable + strings (which can span multiple lines). The caller must free the + returned buffer. For NULL pointers or failure status arguments, + error variables such as h_errno and errno are included in the + result. */ +char *support_format_address_family (int); +char *support_format_addrinfo (struct addrinfo *, int ret); +char *support_format_dns_packet (const unsigned char *buffer, size_t length); +char *support_format_herrno (int); +char *support_format_hostent (struct hostent *); +char *support_format_netent (struct netent *); + +__END_DECLS + +#endif /* SUPPORT_FORMAT_NSS_H */ diff --git a/support/ignore_stderr.c b/support/ignore_stderr.c new file mode 100644 index 0000000000..7b77a2cd56 --- /dev/null +++ b/support/ignore_stderr.c @@ -0,0 +1,38 @@ +/* Avoid all the buffer overflow messages on stderr. + Copyright (C) 2015-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include +#include + +void +ignore_stderr (void) +{ + int fd = open (_PATH_DEVNULL, O_WRONLY); + if (fd == -1) + close (STDERR_FILENO); + else + { + dup2 (fd, STDERR_FILENO); + close (fd); + } + setenv ("LIBC_FATAL_STDERR_", "1", 1); +} diff --git a/support/namespace.h b/support/namespace.h new file mode 100644 index 0000000000..e1ccaa1ef0 --- /dev/null +++ b/support/namespace.h @@ -0,0 +1,65 @@ +/* Entering namespaces for test case isolation. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef SUPPORT_NAMESPACE_H +#define SUPPORT_NAMESPACE_H + +#include +#include + +__BEGIN_DECLS + +/* Attempts to become root (or acquire root-like privileges), possibly + with the help of user namespaces. Return true if (restricted) root + privileges could be attained in some way. Print diagnostics to + standard output. + + Note that this function generally has to be called before a process + becomes multi-threaded, otherwise it may fail with insufficient + privileges on systems which would support this operation for + single-threaded processes. */ +bool support_become_root (void); + +/* Return true if this process can perform a chroot operation. In + general, this is only possible if support_become_root has been + called. Note that the actual test is performed in a subprocess, + after fork, so that the file system root of the original process is + not changed. */ +bool support_can_chroot (void); + +/* Enter a network namespace (and a UTS namespace if possible) and + configure the loopback interface. Return true if a network + namespace could be created. Print diagnostics to standard output. + If a network namespace could be created, but networking in it could + not be configured, terminate the process. It is recommended to + call support_become_root before this function so that the process + has sufficient privileges. */ +bool support_enter_network_namespace (void); + +/* Return true if support_enter_network_namespace managed to enter a + UTS namespace. */ +bool support_in_uts_namespace (void); + +/* Invoke CALLBACK (CLOSURE) in a subprocess created using fork. + Terminate the calling process if the subprocess exits with a + non-zero exit status. */ +void support_isolate_in_subprocess (void (*callback) (void *), void *closure); + +__END_DECLS + +#endif diff --git a/sysdeps/sparc/sparc64/fpu/s_fdimf.S b/support/oom_error.c similarity index 69% rename from sysdeps/sparc/sparc64/fpu/s_fdimf.S rename to support/oom_error.c index 356c23c4e3..7816978273 100644 --- a/sysdeps/sparc/sparc64/fpu/s_fdimf.S +++ b/support/oom_error.c @@ -1,7 +1,6 @@ -/* Compute positive difference, sparc 64-bit. - Copyright (C) 2013-2016 Free Software Foundation, Inc. +/* Reporting out-of-memory errors. + Copyright (C) 2016-2017 Free Software Foundation, Inc. This file is part of the GNU C Library. - Contributed by David S. Miller . The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -17,15 +16,14 @@ License along with the GNU C Library; if not, see . */ -#include +#include -ENTRY(__fdimf) - fcmps %f1, %f3 - fbug 1f - nop - fzeros %f1 - fnegs %f1, %f3 -1: retl - fsubs %f1, %f3, %f0 -END(__fdimf) -weak_alias (__fdimf, fdimf) +#include +#include + +void +oom_error (const char *function, size_t size) +{ + printf ("%s: unable to allocate %zu bytes: %m\n", function, size); + exit (1); +} diff --git a/support/resolv_test.c b/support/resolv_test.c new file mode 100644 index 0000000000..050cd7154b --- /dev/null +++ b/support/resolv_test.c @@ -0,0 +1,1202 @@ +/* DNS test framework and libresolv redirection. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Response builder. */ + +enum + { + max_response_length = 65536 + }; + +/* List of pointers to be freed. The hash table implementation + (struct hsearch_data) does not provide a way to deallocate all + objects, so this approach is used to avoid memory leaks. */ +struct to_be_freed +{ + struct to_be_freed *next; + void *ptr; +}; + +struct resolv_response_builder +{ + const unsigned char *query_buffer; + size_t query_length; + + size_t offset; /* Bytes written so far in buffer. */ + ns_sect section; /* Current section in the DNS packet. */ + unsigned int truncate_bytes; /* Bytes to remove at end of response. */ + bool drop; /* Discard generated response. */ + bool close; /* Close TCP client connection. */ + + /* Offset of the two-byte RDATA length field in the currently + written RDATA sub-structure. 0 if no RDATA is being written. */ + size_t current_rdata_offset; + + /* Hash table for locating targets for label compression. */ + struct hsearch_data compression_offsets; + /* List of pointers which need to be freed. Used for domain names + involved in label compression. */ + struct to_be_freed *to_be_freed; + + /* Must be last. Not zeroed for performance reasons. */ + unsigned char buffer[max_response_length]; +}; + +/* Response builder. */ + +/* Add a pointer to the list of pointers to be freed when B is + deallocated. */ +static void +response_push_pointer_to_free (struct resolv_response_builder *b, void *ptr) +{ + if (ptr == NULL) + return; + struct to_be_freed *e = xmalloc (sizeof (*e)); + *e = (struct to_be_freed) {b->to_be_freed, ptr}; + b->to_be_freed = e; +} + +void +resolv_response_init (struct resolv_response_builder *b, + struct resolv_response_flags flags) +{ + if (b->offset > 0) + FAIL_EXIT1 ("response_init: called at offset %zu", b->offset); + if (b->query_length < 12) + FAIL_EXIT1 ("response_init called for a query of size %zu", + b->query_length); + if (flags.rcode > 15) + FAIL_EXIT1 ("response_init: invalid RCODE %u", flags.rcode); + + /* Copy the transaction ID. */ + b->buffer[0] = b->query_buffer[0]; + b->buffer[1] = b->query_buffer[1]; + + /* Initialize the flags. */ + b->buffer[2] = 0x80; /* Mark as response. */ + b->buffer[2] |= b->query_buffer[2] & 0x01; /* Copy the RD bit. */ + if (flags.tc) + b->buffer[2] |= 0x02; + b->buffer[3] = 0x80 | flags.rcode; /* Always set RA. */ + + /* Fill in the initial section count values. */ + b->buffer[4] = flags.qdcount >> 8; + b->buffer[5] = flags.qdcount; + b->buffer[6] = flags.ancount >> 8; + b->buffer[7] = flags.ancount; + b->buffer[8] = flags.nscount >> 8; + b->buffer[9] = flags.nscount; + b->buffer[10] = flags.adcount >> 8; + b->buffer[11] = flags.adcount; + + b->offset = 12; +} + +void +resolv_response_section (struct resolv_response_builder *b, ns_sect section) +{ + if (b->offset == 0) + FAIL_EXIT1 ("resolv_response_section: response_init not called before"); + if (section < b->section) + FAIL_EXIT1 ("resolv_response_section: cannot go back to previous section"); + b->section = section; +} + +/* Add a single byte to B. */ +static inline void +response_add_byte (struct resolv_response_builder *b, unsigned char ch) +{ + if (b->offset == max_response_length) + FAIL_EXIT1 ("DNS response exceeds 64 KiB limit"); + b->buffer[b->offset] = ch; + ++b->offset; +} + +/* Add a 16-bit word VAL to B, in big-endian format. */ +static void +response_add_16 (struct resolv_response_builder *b, uint16_t val) +{ + response_add_byte (b, val >> 8); + response_add_byte (b, val); +} + +/* Increment the pers-section record counter in the packet header. */ +static void +response_count_increment (struct resolv_response_builder *b) +{ + unsigned int offset = b->section; + offset = 4 + 2 * offset; + ++b->buffer[offset + 1]; + if (b->buffer[offset + 1] == 0) + { + /* Carry. */ + ++b->buffer[offset]; + if (b->buffer[offset] == 0) + /* Overflow. */ + FAIL_EXIT1 ("too many records in section"); + } +} + +void +resolv_response_add_question (struct resolv_response_builder *b, + const char *name, uint16_t class, uint16_t type) +{ + if (b->offset == 0) + FAIL_EXIT1 ("resolv_response_add_question: " + "resolv_response_init not called"); + if (b->section != ns_s_qd) + FAIL_EXIT1 ("resolv_response_add_question: " + "must be called in the question section"); + + resolv_response_add_name (b, name); + response_add_16 (b, type); + response_add_16 (b, class); + + response_count_increment (b); +} + +void +resolv_response_add_name (struct resolv_response_builder *b, + const char *const origname) +{ + /* Normalized name. */ + char *name; + /* Normalized name with case preserved. */ + char *name_case; + { + size_t namelen = strlen (origname); + /* Remove trailing dots. FIXME: Handle trailing quoted dots. */ + while (namelen > 0 && origname[namelen - 1] == '.') + --namelen; + name = xmalloc (namelen + 1); + name_case = xmalloc (namelen + 1); + /* Copy and convert to lowercase. FIXME: This needs to normalize + escaping as well. */ + for (size_t i = 0; i < namelen; ++i) + { + char ch = origname[i]; + name_case[i] = ch; + if ('A' <= ch && ch <= 'Z') + ch = ch - 'A' + 'a'; + name[i] = ch; + } + name[namelen] = 0; + name_case[namelen] = 0; + } + char *name_start = name; + char *name_case_start = name_case; + + bool compression = false; + while (*name) + { + /* Search for a previous name we can reference. */ + ENTRY new_entry = + { + .key = name, + .data = (void *) (uintptr_t) b->offset, + }; + + /* If the label can be a compression target because it is at a + reachable offset, add it to the hash table. */ + ACTION action; + if (b->offset < (1 << 12)) + action = ENTER; + else + action = FIND; + + /* Search for known compression offsets in the hash table. */ + ENTRY *e; + if (hsearch_r (new_entry, action, &e, &b->compression_offsets) == 0) + { + if (action == FIND && errno == ESRCH) + /* Fall through. */ + e = NULL; + else + FAIL_EXIT1 ("hsearch_r failure in name compression: %m"); + } + + /* The name is known. Reference the previous location. */ + if (e != NULL && e->data != new_entry.data) + { + size_t old_offset = (uintptr_t) e->data; + response_add_byte (b, 0xC0 | (old_offset >> 8)); + response_add_byte (b, old_offset); + compression = true; + break; + } + + /* The name does not exist yet. Write one label. First, add + room for the label length. */ + size_t buffer_label_offset = b->offset; + response_add_byte (b, 0); + + /* Copy the label. */ + while (true) + { + char ch = *name_case; + if (ch == '\0') + break; + ++name; + ++name_case; + if (ch == '.') + break; + /* FIXME: Handle escaping. */ + response_add_byte (b, ch); + } + + /* Patch in the label length. */ + size_t label_length = b->offset - buffer_label_offset - 1; + if (label_length == 0) + FAIL_EXIT1 ("empty label in name compression: %s", origname); + if (label_length > 63) + FAIL_EXIT1 ("label too long in name compression: %s", origname); + b->buffer[buffer_label_offset] = label_length; + + /* Continue with the tail of the name and the next label. */ + } + + if (compression) + { + /* If we found an immediate match for the name, we have not put + it into the hash table, and can free it immediately. */ + if (name == name_start) + free (name_start); + else + response_push_pointer_to_free (b, name_start); + } + else + { + /* Terminate the sequence of labels. With compression, this is + implicit in the compression reference. */ + response_add_byte (b, 0); + response_push_pointer_to_free (b, name_start); + } + + free (name_case_start); +} + +void +resolv_response_open_record (struct resolv_response_builder *b, + const char *name, + uint16_t class, uint16_t type, uint32_t ttl) +{ + if (b->section == ns_s_qd) + FAIL_EXIT1 ("resolv_response_open_record called in question section"); + if (b->current_rdata_offset != 0) + FAIL_EXIT1 ("resolv_response_open_record called with open record"); + + resolv_response_add_name (b, name); + response_add_16 (b, type); + response_add_16 (b, class); + response_add_16 (b, ttl >> 16); + response_add_16 (b, ttl); + + b->current_rdata_offset = b->offset; + /* Add room for the RDATA length. */ + response_add_16 (b, 0); +} + + +void +resolv_response_close_record (struct resolv_response_builder *b) +{ + size_t rdata_offset = b->current_rdata_offset; + if (rdata_offset == 0) + FAIL_EXIT1 ("response_close_record called without open record"); + size_t rdata_length = b->offset - rdata_offset - 2; + if (rdata_length > 65535) + FAIL_EXIT1 ("RDATA length %zu exceeds limit", rdata_length); + b->buffer[rdata_offset] = rdata_length >> 8; + b->buffer[rdata_offset + 1] = rdata_length; + response_count_increment (b); + b->current_rdata_offset = 0; +} + +void +resolv_response_add_data (struct resolv_response_builder *b, + const void *data, size_t length) +{ + size_t remaining = max_response_length - b->offset; + if (remaining < length) + FAIL_EXIT1 ("resolv_response_add_data: not enough room for %zu bytes", + length); + memcpy (b->buffer + b->offset, data, length); + b->offset += length; +} + +void +resolv_response_drop (struct resolv_response_builder *b) +{ + b->drop = true; +} + +void +resolv_response_close (struct resolv_response_builder *b) +{ + b->close = true; +} + +void +resolv_response_truncate_data (struct resolv_response_builder *b, size_t count) +{ + if (count > 65535) + FAIL_EXIT1 ("resolv_response_truncate_data: argument too large: %zu", + count); + b->truncate_bytes = count; +} + + +size_t +resolv_response_length (const struct resolv_response_builder *b) +{ + return b->offset; +} + +unsigned char * +resolv_response_buffer (const struct resolv_response_builder *b) +{ + unsigned char *result = xmalloc (b->offset); + memcpy (result, b->buffer, b->offset); + return result; +} + +static struct resolv_response_builder * +response_builder_allocate + (const unsigned char *query_buffer, size_t query_length) +{ + struct resolv_response_builder *b = xmalloc (sizeof (*b)); + memset (b, 0, offsetof (struct resolv_response_builder, buffer)); + b->query_buffer = query_buffer; + b->query_length = query_length; + TEST_VERIFY_EXIT (hcreate_r (10000, &b->compression_offsets) != 0); + return b; +} + +static void +response_builder_free (struct resolv_response_builder *b) +{ + struct to_be_freed *current = b->to_be_freed; + while (current != NULL) + { + struct to_be_freed *next = current->next; + free (current->ptr); + free (current); + current = next; + } + hdestroy_r (&b->compression_offsets); + free (b); +} + +/* DNS query processing. */ + +/* Data extracted from the question section of a DNS packet. */ +struct query_info +{ + char qname[MAXDNAME]; + uint16_t qclass; + uint16_t qtype; + struct resolv_edns_info edns; +}; + +/* Update *INFO from the specified DNS packet. */ +static void +parse_query (struct query_info *info, + const unsigned char *buffer, size_t length) +{ + HEADER hd; + _Static_assert (sizeof (hd) == 12, "DNS header size"); + if (length < sizeof (hd)) + FAIL_EXIT1 ("malformed DNS query: too short: %zu bytes", length); + memcpy (&hd, buffer, sizeof (hd)); + + if (ntohs (hd.qdcount) != 1) + FAIL_EXIT1 ("malformed DNS query: wrong question count: %d", + (int) ntohs (hd.qdcount)); + if (ntohs (hd.ancount) != 0) + FAIL_EXIT1 ("malformed DNS query: wrong answer count: %d", + (int) ntohs (hd.ancount)); + if (ntohs (hd.nscount) != 0) + FAIL_EXIT1 ("malformed DNS query: wrong authority count: %d", + (int) ntohs (hd.nscount)); + if (ntohs (hd.arcount) > 1) + FAIL_EXIT1 ("malformed DNS query: wrong additional count: %d", + (int) ntohs (hd.arcount)); + + int ret = dn_expand (buffer, buffer + length, buffer + sizeof (hd), + info->qname, sizeof (info->qname)); + if (ret < 0) + FAIL_EXIT1 ("malformed DNS query: cannot uncompress QNAME"); + + /* Obtain QTYPE and QCLASS. */ + size_t remaining = length - (12 + ret); + struct + { + uint16_t qtype; + uint16_t qclass; + } qtype_qclass; + if (remaining < sizeof (qtype_qclass)) + FAIL_EXIT1 ("malformed DNS query: " + "query lacks QCLASS/QTYPE, QNAME: %s", info->qname); + memcpy (&qtype_qclass, buffer + 12 + ret, sizeof (qtype_qclass)); + info->qclass = ntohs (qtype_qclass.qclass); + info->qtype = ntohs (qtype_qclass.qtype); + + memset (&info->edns, 0, sizeof (info->edns)); + if (ntohs (hd.arcount) > 0) + { + /* Parse EDNS record. */ + struct __attribute__ ((packed, aligned (1))) + { + uint8_t root; + uint16_t rtype; + uint16_t payload; + uint8_t edns_extended_rcode; + uint8_t edns_version; + uint16_t flags; + uint16_t rdatalen; + } rr; + _Static_assert (sizeof (rr) == 11, "EDNS record size"); + + if (remaining < 4 + sizeof (rr)) + FAIL_EXIT1 ("mailformed DNS query: no room for EDNS record"); + memcpy (&rr, buffer + 12 + ret + 4, sizeof (rr)); + if (rr.root != 0) + FAIL_EXIT1 ("malformed DNS query: invalid OPT RNAME: %d\n", rr.root); + if (rr.rtype != htons (41)) + FAIL_EXIT1 ("malformed DNS query: invalid OPT type: %d\n", + ntohs (rr.rtype)); + info->edns.active = true; + info->edns.extended_rcode = rr.edns_extended_rcode; + info->edns.version = rr.edns_version; + info->edns.flags = ntohs (rr.flags); + info->edns.payload_size = ntohs (rr.payload); + } +} + + +/* Main testing framework. */ + +/* Per-server information. One struct is allocated for each test + server. */ +struct resolv_test_server +{ + /* Local address of the server. UDP and TCP use the same port. */ + struct sockaddr_in address; + + /* File descriptor of the UDP server, or -1 if this server is + disabled. */ + int socket_udp; + + /* File descriptor of the TCP server, or -1 if this server is + disabled. */ + int socket_tcp; + + /* Counter of the number of responses processed so far. */ + size_t response_number; + + /* Thread handles for the server threads (if not disabled in the + configuration). */ + pthread_t thread_udp; + pthread_t thread_tcp; +}; + +/* Main struct for keeping track of libresolv redirection and + testing. */ +struct resolv_test +{ + /* After initialization, any access to the struct must be performed + while this lock is acquired. */ + pthread_mutex_t lock; + + /* Data for each test server. */ + struct resolv_test_server servers[resolv_max_test_servers]; + + /* Used if config.single_thread_udp is true. */ + pthread_t thread_udp_single; + + struct resolv_redirect_config config; + bool termination_requested; +}; + +/* Function implementing a server thread. */ +typedef void (*thread_callback) (struct resolv_test *, int server_index); + +/* Storage for thread-specific data, for passing to the + thread_callback function. */ +struct thread_closure +{ + struct resolv_test *obj; /* Current test object. */ + thread_callback callback; /* Function to call. */ + int server_index; /* Index of the implemented server. */ +}; + +/* Wrap response_callback as a function which can be passed to + pthread_create. */ +static void * +thread_callback_wrapper (void *arg) +{ + struct thread_closure *closure = arg; + closure->callback (closure->obj, closure->server_index); + free (closure); + return NULL; +} + +/* Start a server thread for the specified SERVER_INDEX, implemented + by CALLBACK. */ +static pthread_t +start_server_thread (struct resolv_test *obj, int server_index, + thread_callback callback) +{ + struct thread_closure *closure = xmalloc (sizeof (*closure)); + *closure = (struct thread_closure) + { + .obj = obj, + .callback = callback, + .server_index = server_index, + }; + return xpthread_create (NULL, thread_callback_wrapper, closure); +} + +/* Process one UDP query. Return false if a termination requested has + been detected. */ +static bool +server_thread_udp_process_one (struct resolv_test *obj, int server_index) +{ + unsigned char query[512]; + struct sockaddr_storage peer; + socklen_t peerlen = sizeof (peer); + size_t length = xrecvfrom (obj->servers[server_index].socket_udp, + query, sizeof (query), 0, + (struct sockaddr *) &peer, &peerlen); + /* Check for termination. */ + { + bool termination_requested; + xpthread_mutex_lock (&obj->lock); + termination_requested = obj->termination_requested; + xpthread_mutex_unlock (&obj->lock); + if (termination_requested) + return false; + } + + + struct query_info qinfo; + parse_query (&qinfo, query, length); + if (test_verbose > 0) + { + if (test_verbose > 1) + printf ("info: UDP server %d: incoming query:" + " %zd bytes, %s/%u/%u, tnxid=0x%02x%02x\n", + server_index, length, qinfo.qname, qinfo.qclass, qinfo.qtype, + query[0], query[1]); + else + printf ("info: UDP server %d: incoming query:" + " %zd bytes, %s/%u/%u\n", + server_index, length, qinfo.qname, qinfo.qclass, qinfo.qtype); + } + + struct resolv_response_context ctx = + { + .query_buffer = query, + .query_length = length, + .server_index = server_index, + .tcp = false, + .edns = qinfo.edns, + }; + struct resolv_response_builder *b = response_builder_allocate (query, length); + obj->config.response_callback + (&ctx, b, qinfo.qname, qinfo.qclass, qinfo.qtype); + + if (b->drop) + { + if (test_verbose) + printf ("info: UDP server %d: dropping response to %s/%u/%u\n", + server_index, qinfo.qname, qinfo.qclass, qinfo.qtype); + } + else + { + if (test_verbose) + { + if (b->offset >= 12) + printf ("info: UDP server %d: sending response:" + " %zu bytes, RCODE %d (for %s/%u/%u)\n", + server_index, b->offset, b->buffer[3] & 0x0f, + qinfo.qname, qinfo.qclass, qinfo.qtype); + else + printf ("info: UDP server %d: sending response: %zu bytes" + " (for %s/%u/%u)\n", + server_index, b->offset, + qinfo.qname, qinfo.qclass, qinfo.qtype); + if (b->truncate_bytes > 0) + printf ("info: truncated by %u bytes\n", b->truncate_bytes); + } + size_t to_send = b->offset; + if (to_send < b->truncate_bytes) + to_send = 0; + else + to_send -= b->truncate_bytes; + + /* Ignore most errors here because the other end may have closed + the socket. */ + if (sendto (obj->servers[server_index].socket_udp, + b->buffer, to_send, 0, + (struct sockaddr *) &peer, peerlen) < 0) + TEST_VERIFY_EXIT (errno != EBADF); + } + response_builder_free (b); + return true; +} + +/* UDP thread_callback function. Variant for one thread per + server. */ +static void +server_thread_udp (struct resolv_test *obj, int server_index) +{ + while (server_thread_udp_process_one (obj, server_index)) + ; +} + +/* Single-threaded UDP processing function, for the single_thread_udp + case. */ +static void * +server_thread_udp_single (void *closure) +{ + struct resolv_test *obj = closure; + + struct pollfd fds[resolv_max_test_servers]; + for (int server_index = 0; server_index < resolv_max_test_servers; + ++server_index) + if (obj->config.servers[server_index].disable_udp) + fds[server_index] = (struct pollfd) {.fd = -1}; + else + { + fds[server_index] = (struct pollfd) + { + .fd = obj->servers[server_index].socket_udp, + .events = POLLIN + }; + + /* Make the socket non-blocking. */ + int flags = fcntl (obj->servers[server_index].socket_udp, F_GETFL, 0); + if (flags < 0) + FAIL_EXIT1 ("fcntl (F_GETFL): %m"); + flags |= O_NONBLOCK; + if (fcntl (obj->servers[server_index].socket_udp, F_SETFL, flags) < 0) + FAIL_EXIT1 ("fcntl (F_SETFL): %m"); + } + + while (true) + { + xpoll (fds, resolv_max_test_servers, -1); + for (int server_index = 0; server_index < resolv_max_test_servers; + ++server_index) + if (fds[server_index].revents != 0) + { + if (!server_thread_udp_process_one (obj, server_index)) + goto out; + fds[server_index].revents = 0; + } + } + + out: + return NULL; +} + +/* Start the single UDP handler thread (for the single_thread_udp + case). */ +static void +start_server_thread_udp_single (struct resolv_test *obj) +{ + obj->thread_udp_single + = xpthread_create (NULL, server_thread_udp_single, obj); +} + +/* Data describing a TCP client connect. */ +struct tcp_thread_closure +{ + struct resolv_test *obj; + int server_index; + int client_socket; +}; + +/* Read a complete DNS query packet. If EOF_OK, an immediate + end-of-file condition is acceptable. */ +static bool +read_fully (int fd, void *buf, size_t len, bool eof_ok) +{ + const void *const end = buf + len; + while (buf < end) + { + ssize_t ret = read (fd, buf, end - buf); + if (ret == 0) + { + if (!eof_ok) + { + support_record_failure (); + printf ("error: unexpected EOF on TCP connection\n"); + } + return false; + } + else if (ret < 0) + { + if (!eof_ok || errno != ECONNRESET) + { + support_record_failure (); + printf ("error: TCP read: %m\n"); + } + return false; + } + buf += ret; + eof_ok = false; + } + return true; +} + +/* Write an array of iovecs. Terminate the process on failure. */ +static void +writev_fully (int fd, struct iovec *buffers, size_t count) +{ + while (count > 0) + { + /* Skip zero-length write requests. */ + if (buffers->iov_len == 0) + { + ++buffers; + --count; + continue; + } + /* Try to rewrite the remaing buffers. */ + ssize_t ret = writev (fd, buffers, count); + if (ret < 0) + FAIL_EXIT1 ("writev: %m"); + if (ret == 0) + FAIL_EXIT1 ("writev: invalid return value zero"); + /* Find the buffers that were successfully written. */ + while (ret > 0) + { + if (count == 0) + FAIL_EXIT1 ("internal writev consistency failure"); + /* Current buffer was partially written. */ + if (buffers->iov_len > (size_t) ret) + { + buffers->iov_base += ret; + buffers->iov_len -= ret; + ret = 0; + } + else + { + ret -= buffers->iov_len; + buffers->iov_len = 0; + ++buffers; + --count; + } + } + } +} + +/* Thread callback for handling a single established TCP connection to + a client. */ +static void * +server_thread_tcp_client (void *arg) +{ + struct tcp_thread_closure *closure = arg; + + while (true) + { + /* Read packet length. */ + uint16_t query_length; + if (!read_fully (closure->client_socket, + &query_length, sizeof (query_length), true)) + break; + query_length = ntohs (query_length); + + /* Read the packet. */ + unsigned char *query_buffer = xmalloc (query_length); + read_fully (closure->client_socket, query_buffer, query_length, false); + + struct query_info qinfo; + parse_query (&qinfo, query_buffer, query_length); + if (test_verbose > 0) + { + if (test_verbose > 1) + printf ("info: UDP server %d: incoming query:" + " %d bytes, %s/%u/%u, tnxid=0x%02x%02x\n", + closure->server_index, query_length, + qinfo.qname, qinfo.qclass, qinfo.qtype, + query_buffer[0], query_buffer[1]); + else + printf ("info: TCP server %d: incoming query:" + " %u bytes, %s/%u/%u\n", + closure->server_index, query_length, + qinfo.qname, qinfo.qclass, qinfo.qtype); + } + + struct resolv_response_context ctx = + { + .query_buffer = query_buffer, + .query_length = query_length, + .server_index = closure->server_index, + .tcp = true, + .edns = qinfo.edns, + }; + struct resolv_response_builder *b = response_builder_allocate + (query_buffer, query_length); + closure->obj->config.response_callback + (&ctx, b, qinfo.qname, qinfo.qclass, qinfo.qtype); + + if (b->drop) + { + if (test_verbose) + printf ("info: TCP server %d: dropping response to %s/%u/%u\n", + closure->server_index, + qinfo.qname, qinfo.qclass, qinfo.qtype); + } + else + { + if (test_verbose) + printf ("info: TCP server %d: sending response: %zu bytes" + " (for %s/%u/%u)\n", + closure->server_index, b->offset, + qinfo.qname, qinfo.qclass, qinfo.qtype); + uint16_t length = htons (b->offset); + size_t to_send = b->offset; + if (to_send < b->truncate_bytes) + to_send = 0; + else + to_send -= b->truncate_bytes; + struct iovec buffers[2] = + { + {&length, sizeof (length)}, + {b->buffer, to_send} + }; + writev_fully (closure->client_socket, buffers, 2); + } + bool close_flag = b->close; + response_builder_free (b); + free (query_buffer); + if (close_flag) + break; + } + + xclose (closure->client_socket); + free (closure); + return NULL; +} + +/* thread_callback for the TCP case. Accept connections and create a + new thread for each client. */ +static void +server_thread_tcp (struct resolv_test *obj, int server_index) +{ + while (true) + { + /* Get the client conenction. */ + int client_socket = xaccept + (obj->servers[server_index].socket_tcp, NULL, NULL); + + /* Check for termination. */ + xpthread_mutex_lock (&obj->lock); + if (obj->termination_requested) + { + xpthread_mutex_unlock (&obj->lock); + xclose (client_socket); + break; + } + xpthread_mutex_unlock (&obj->lock); + + /* Spawn a new thread for handling this connection. */ + struct tcp_thread_closure *closure = xmalloc (sizeof (*closure)); + *closure = (struct tcp_thread_closure) + { + .obj = obj, + .server_index = server_index, + .client_socket = client_socket, + }; + + pthread_t thr + = xpthread_create (NULL, server_thread_tcp_client, closure); + /* TODO: We should keep track of this thread so that we can + block in resolv_test_end until it has exited. */ + xpthread_detach (thr); + } +} + +/* Create UDP and TCP server sockets. */ +static void +make_server_sockets (struct resolv_test_server *server) +{ + while (true) + { + server->socket_udp = xsocket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); + server->socket_tcp = xsocket (AF_INET, SOCK_STREAM, IPPROTO_TCP); + + /* Pick the address for the UDP socket. */ + server->address = (struct sockaddr_in) + { + .sin_family = AF_INET, + .sin_addr = {.s_addr = htonl (INADDR_LOOPBACK)} + }; + xbind (server->socket_udp, + (struct sockaddr *)&server->address, sizeof (server->address)); + + /* Retrieve the address. */ + socklen_t addrlen = sizeof (server->address); + xgetsockname (server->socket_udp, + (struct sockaddr *)&server->address, &addrlen); + + /* Bind the TCP socket to the same address. */ + { + int on = 1; + xsetsockopt (server->socket_tcp, SOL_SOCKET, SO_REUSEADDR, + &on, sizeof (on)); + } + if (bind (server->socket_tcp, + (struct sockaddr *)&server->address, + sizeof (server->address)) != 0) + { + /* Port collision. The UDP bind succeeded, but the TCP BIND + failed. We assume here that the kernel will pick the + next local UDP address randomly. */ + if (errno == EADDRINUSE) + { + xclose (server->socket_udp); + xclose (server->socket_tcp); + continue; + } + FAIL_EXIT1 ("TCP bind: %m"); + } + xlisten (server->socket_tcp, 5); + break; + } +} + +/* One-time initialization of NSS. */ +static void +resolv_redirect_once (void) +{ + /* Only use nss_dns. */ + __nss_configure_lookup ("hosts", "dns"); + __nss_configure_lookup ("networks", "dns"); + /* Enter a network namespace for isolation and firewall state + cleanup. The tests will still work if these steps fail, but they + may be less reliable. */ + support_become_root (); + support_enter_network_namespace (); +} +pthread_once_t resolv_redirect_once_var = PTHREAD_ONCE_INIT; + +void +resolv_test_init (void) +{ + /* Perform one-time initialization of NSS. */ + xpthread_once (&resolv_redirect_once_var, resolv_redirect_once); +} + +/* Copy the search path from CONFIG.search to the _res object. */ +static void +set_search_path (struct resolv_redirect_config config) +{ + memset (_res.defdname, 0, sizeof (_res.defdname)); + memset (_res.dnsrch, 0, sizeof (_res.dnsrch)); + + char *current = _res.defdname; + char *end = current + sizeof (_res.defdname); + + for (unsigned int i = 0; + i < sizeof (config.search) / sizeof (config.search[0]); ++i) + { + if (config.search[i] == NULL) + continue; + + size_t length = strlen (config.search[i]) + 1; + size_t remaining = end - current; + TEST_VERIFY_EXIT (length <= remaining); + memcpy (current, config.search[i], length); + _res.dnsrch[i] = current; + current += length; + } +} + +struct resolv_test * +resolv_test_start (struct resolv_redirect_config config) +{ + /* Apply configuration defaults. */ + if (config.nscount == 0) + config.nscount = resolv_max_test_servers; + + struct resolv_test *obj = xmalloc (sizeof (*obj)); + *obj = (struct resolv_test) { + .config = config, + .lock = PTHREAD_MUTEX_INITIALIZER, + }; + + resolv_test_init (); + + /* Create all the servers, to reserve the necessary ports. */ + for (int server_index = 0; server_index < config.nscount; ++server_index) + make_server_sockets (obj->servers + server_index); + + /* Start server threads. Disable the server ports, as + requested. */ + for (int server_index = 0; server_index < config.nscount; ++server_index) + { + struct resolv_test_server *server = obj->servers + server_index; + if (config.servers[server_index].disable_udp) + { + xclose (server->socket_udp); + server->socket_udp = -1; + } + else if (!config.single_thread_udp) + server->thread_udp = start_server_thread (obj, server_index, + server_thread_udp); + if (config.servers[server_index].disable_tcp) + { + xclose (server->socket_tcp); + server->socket_tcp = -1; + } + else + server->thread_tcp = start_server_thread (obj, server_index, + server_thread_tcp); + } + if (config.single_thread_udp) + start_server_thread_udp_single (obj); + + int timeout = 1; + + /* Initialize libresolv. */ + TEST_VERIFY_EXIT (res_init () == 0); + + /* Disable IPv6 name server addresses. The code below only + overrides the IPv4 addresses. */ + __res_iclose (&_res, true); + _res._u._ext.nscount = 0; + + /* Redirect queries to the server socket. */ + if (test_verbose) + { + printf ("info: old timeout value: %d\n", _res.retrans); + printf ("info: old retry attempt value: %d\n", _res.retry); + printf ("info: old _res.options: 0x%lx\n", _res.options); + printf ("info: old _res.nscount value: %d\n", _res.nscount); + printf ("info: old _res.ndots value: %d\n", _res.ndots); + } + _res.retrans = timeout; + _res.retry = 4; + _res.nscount = config.nscount; + _res.options = RES_INIT | RES_RECURSE | RES_DEFNAMES | RES_DNSRCH; + _res.ndots = 1; + if (test_verbose) + { + printf ("info: new timeout value: %d\n", _res.retrans); + printf ("info: new retry attempt value: %d\n", _res.retry); + printf ("info: new _res.options: 0x%lx\n", _res.options); + printf ("info: new _res.nscount value: %d\n", _res.nscount); + printf ("info: new _res.ndots value: %d\n", _res.ndots); + } + for (int server_index = 0; server_index < config.nscount; ++server_index) + { + _res.nsaddr_list[server_index] = obj->servers[server_index].address; + if (test_verbose) + { + char buf[256]; + TEST_VERIFY_EXIT + (inet_ntop (AF_INET, &obj->servers[server_index].address.sin_addr, + buf, sizeof (buf)) != NULL); + printf ("info: server %d: %s/%u\n", + server_index, buf, + htons (obj->servers[server_index].address.sin_port)); + } + } + + set_search_path (config); + + return obj; +} + +void +resolv_test_end (struct resolv_test *obj) +{ + res_close (); + + xpthread_mutex_lock (&obj->lock); + obj->termination_requested = true; + xpthread_mutex_unlock (&obj->lock); + + /* Send trigger packets to unblock the server threads. */ + for (int server_index = 0; server_index < obj->config.nscount; + ++server_index) + { + if (!obj->config.servers[server_index].disable_udp) + { + int sock = xsocket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); + xsendto (sock, "", 1, 0, + (struct sockaddr *) &obj->servers[server_index].address, + sizeof (obj->servers[server_index].address)); + xclose (sock); + } + if (!obj->config.servers[server_index].disable_tcp) + { + int sock = xsocket (AF_INET, SOCK_STREAM, IPPROTO_TCP); + xconnect (sock, + (struct sockaddr *) &obj->servers[server_index].address, + sizeof (obj->servers[server_index].address)); + xclose (sock); + } + } + + if (obj->config.single_thread_udp) + xpthread_join (obj->thread_udp_single); + + /* Wait for the server threads to terminate. */ + for (int server_index = 0; server_index < obj->config.nscount; + ++server_index) + { + if (!obj->config.servers[server_index].disable_udp) + { + if (!obj->config.single_thread_udp) + xpthread_join (obj->servers[server_index].thread_udp); + xclose (obj->servers[server_index].socket_udp); + } + if (!obj->config.servers[server_index].disable_tcp) + { + xpthread_join (obj->servers[server_index].thread_tcp); + xclose (obj->servers[server_index].socket_tcp); + } + } + + free (obj); +} diff --git a/support/resolv_test.h b/support/resolv_test.h new file mode 100644 index 0000000000..6498751569 --- /dev/null +++ b/support/resolv_test.h @@ -0,0 +1,180 @@ +/* DNS test framework and libresolv redirection. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef SUPPORT_RESOLV_TEST_H +#define SUPPORT_RESOLV_TEST_H + +#include +#include +#include + +__BEGIN_DECLS + +/* Information about EDNS properties of a DNS query. */ +struct resolv_edns_info +{ + bool active; + uint8_t extended_rcode; + uint8_t version; + uint16_t flags; + uint16_t payload_size; +}; + +/* This struct provides context information when the response callback + specified in struct resolv_redirect_config is invoked. */ +struct resolv_response_context +{ + const unsigned char *query_buffer; + size_t query_length; + int server_index; + bool tcp; + struct resolv_edns_info edns; +}; + +/* This opaque struct is used to construct responses from within the + response callback function. */ +struct resolv_response_builder; + +/* This opaque struct collects information about the resolver testing + currently in progress. */ +struct resolv_test; + +enum + { + /* Maximum number of test servers supported by the framework. */ + resolv_max_test_servers = 3, + }; + +/* Configuration settings specific to individual test servers. */ +struct resolv_redirect_server_config +{ + bool disable_tcp; /* If true, no TCP server is listening. */ + bool disable_udp; /* If true, no UDP server is listening. */ +}; + +/* Instructions for setting up the libresolv redirection. */ +struct resolv_redirect_config +{ + /* The response_callback function is called for every incoming DNS + packet, over UDP or TCP. It must be specified, the other + configuration settings are optional. */ + void (*response_callback) (const struct resolv_response_context *, + struct resolv_response_builder *, + const char *qname, + uint16_t qclass, uint16_t qtype); + + /* Per-server configuration. */ + struct resolv_redirect_server_config servers[resolv_max_test_servers]; + + /* Search path entries. The first entry serves as the default + domain name as well. */ + const char *search[7]; + + /* Number of servers to activate in resolv. 0 means the default, + resolv_max_test_servers. */ + int nscount; + + /* If true, use a single thread to process all UDP queries. This + may results in more predictable ordering of queries and + responses. */ + bool single_thread_udp; +}; + +/* Configure NSS to use, nss_dns only for aplicable databases, and try + to put the process into a network namespace for better isolation. + This may have to be called before resolv_test_start, before the + process creates any threads. Otherwise, initialization is + performed by resolv_test_start implicitly. */ +void resolv_test_init (void); + +/* Initiate resolver testing. This updates the _res variable as + needed. As a side effect, NSS is reconfigured to use nss_dns only + for aplicable databases, and the process may enter a network + namespace for better isolation. */ +struct resolv_test *resolv_test_start (struct resolv_redirect_config); + +/* Call this function at the end of resolver testing, to free + resources and report pending errors (if any). */ +void resolv_test_end (struct resolv_test *); + +/* The remaining facilities in this file are used for constructing + response packets from the response_callback function. */ + +/* Special settings for constructing responses from the callback. */ +struct resolv_response_flags +{ + /* 4-bit response code to incorporate into the response. */ + unsigned char rcode; + + /* If true, the TC (truncation) flag will be set. */ + bool tc; + + /* Initial section count values. Can be used to artificially + increase the counts, for malformed packet testing.*/ + unsigned short qdcount; + unsigned short ancount; + unsigned short nscount; + unsigned short adcount; +}; + +/* Begin a new response with the requested flags. Must be called + first. */ +void resolv_response_init (struct resolv_response_builder *, + struct resolv_response_flags); + +/* Switches to the section in the response packet. Only forward + movement is supported. */ +void resolv_response_section (struct resolv_response_builder *, ns_sect); + +/* Add a question record to the question section. */ +void resolv_response_add_question (struct resolv_response_builder *, + const char *name, uint16_t class, + uint16_t type); +/* Starts a new resource record with the specified owner name, class, + type, and TTL. Data is supplied with resolv_response_add_data or + resolv_response_add_name. */ +void resolv_response_open_record (struct resolv_response_builder *, + const char *name, uint16_t class, + uint16_t type, uint32_t ttl); + +/* Add unstructed bytes to the RDATA part of a resource record. */ +void resolv_response_add_data (struct resolv_response_builder *, + const void *, size_t); + +/* Add a compressed domain name to the RDATA part of a resource + record. */ +void resolv_response_add_name (struct resolv_response_builder *, + const char *name); + +/* Mark the end of the constructed record. Must be called last. */ +void resolv_response_close_record (struct resolv_response_builder *); + +/* Drop this query packet (that is, do not send a response, not even + an empty packet). */ +void resolv_response_drop (struct resolv_response_builder *); + +/* In TCP mode, close the connection after this packet (if a response + is sent). */ +void resolv_response_close (struct resolv_response_builder *); + +/* The size of the response packet built so far. */ +size_t resolv_response_length (const struct resolv_response_builder *); + +__END_DECLS + +#endif /* SUPPORT_RESOLV_TEST_H */ diff --git a/support/run_diff.h b/support/run_diff.h new file mode 100644 index 0000000000..f65b5dd22c --- /dev/null +++ b/support/run_diff.h @@ -0,0 +1,31 @@ +/* Invoke the system diff tool to compare two strings. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef SUPPORT_RUN_DIFF_H +#define SUPPORT_RUN_DIFF_H + +/* Compare the two NUL-terminated strings LEFT and RIGHT using the + diff tool. Label the sides of the diff with LEFT_LABEL and + RIGHT_LABEL, respectively. + + This function assumes that LEFT and RIGHT are different + strings. */ +void support_run_diff (const char *left_label, const char *left, + const char *right_label, const char *right); + +#endif /* SUPPORT_RUN_DIFF_H */ diff --git a/support/set_fortify_handler.c b/support/set_fortify_handler.c new file mode 100644 index 0000000000..f434a8082a --- /dev/null +++ b/support/set_fortify_handler.c @@ -0,0 +1,34 @@ +/* Set signal handler for use in fortify tests. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include + +void +set_fortify_handler (void (*handler) (int sig)) +{ + struct sigaction sa; + + sa.sa_handler = handler; + sa.sa_flags = 0; + sigemptyset (&sa.sa_mask); + + sigaction (SIGABRT, &sa, NULL); + ignore_stderr (); +} diff --git a/support/support-xstat.c b/support/support-xstat.c new file mode 100644 index 0000000000..86a81ec601 --- /dev/null +++ b/support/support-xstat.c @@ -0,0 +1,30 @@ +/* stat64 with error checking. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +/* NB: Non-standard file name to avoid sysdeps override for xstat. */ + +#include +#include +#include + +void +xstat (const char *path, struct stat64 *result) +{ + if (stat64 (path, result) != 0) + FAIL_EXIT1 ("stat64 (\"%s\"): %m", path); +} diff --git a/support/support.h b/support/support.h new file mode 100644 index 0000000000..4b5f04c2cc --- /dev/null +++ b/support/support.h @@ -0,0 +1,74 @@ +/* Common extra functions. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +/* This header file should only contain definitions compatible with + C90. (Using __attribute__ is fine because provides a + fallback.) */ + +#ifndef SUPPORT_H +#define SUPPORT_H + +#include +#include + +__BEGIN_DECLS + +/* Write a message to standard output. Can be used in signal + handlers. */ +void write_message (const char *message) __attribute__ ((nonnull (1))); + +/* Avoid all the buffer overflow messages on stderr. */ +void ignore_stderr (void); + +/* Set fortification error handler. Used when tests want to verify that bad + code is caught by the library. */ +void set_fortify_handler (void (*handler) (int sig)); + +/* Report an out-of-memory error for the allocation of SIZE bytes in + FUNCTION, terminating the process. */ +void oom_error (const char *function, size_t size) + __attribute__ ((nonnull (1))); + +/* Return a pointer to a memory region of SIZE bytes. The memory is + initialized to zero and will be shared with subprocesses (across + fork). The returned pointer must be freed using + support_shared_free; it is not compatible with the malloc + functions. */ +void *support_shared_allocate (size_t size); + +/* Deallocate a pointer returned by support_shared_allocate. */ +void support_shared_free (void *); + +/* Write CONTENTS to the file PATH. Create or truncate the file as + needed. The file mode is 0666 masked by the umask. Terminate the + process on error. */ +void support_write_file_string (const char *path, const char *contents); + +/* Error-checking wrapper functions which terminate the process on + error. */ + +void *xmalloc (size_t) __attribute__ ((malloc)); +void *xcalloc (size_t n, size_t s) __attribute__ ((malloc)); +void *xrealloc (void *p, size_t n); +char *xasprintf (const char *format, ...) + __attribute__ ((format (printf, 1, 2), malloc)); +char *xstrdup (const char *); + +__END_DECLS + +#endif /* SUPPORT_H */ diff --git a/sysdeps/sparc/sparc32/sparcv9/fpu/s_fdim.S b/support/support_become_root.c similarity index 57% rename from sysdeps/sparc/sparc32/sparcv9/fpu/s_fdim.S rename to support/support_become_root.c index 37f7f44dfa..3fa0bd4ac0 100644 --- a/sysdeps/sparc/sparc32/sparcv9/fpu/s_fdim.S +++ b/support/support_become_root.c @@ -1,7 +1,6 @@ -/* Compute positive difference, sparc 32-bit+v9. - Copyright (C) 2013-2016 Free Software Foundation, Inc. +/* Acquire root privileges. + Copyright (C) 2016-2017 Free Software Foundation, Inc. This file is part of the GNU C Library. - Contributed by David S. Miller . The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -17,24 +16,25 @@ License along with the GNU C Library; if not, see . */ -#include -#include +#include -ENTRY(__fdim) - std %o0, [%sp + 72] - std %o2, [%sp + 80] - ldd [%sp + 72], %f0 - ldd [%sp + 80], %f2 - fcmpd %f0, %f2 - fbug 1f - nop - fzero %f0 - fnegd %f0, %f2 -1: retl - fsubd %f0, %f2, %f0 -END(__fdim) -weak_alias (__fdim, fdim) +#include +#include +#include -#if LONG_DOUBLE_COMPAT(libm, GLIBC_2_1) -compat_symbol (libm, __fdim, fdiml, GLIBC_2_1); +bool +support_become_root (void) +{ +#ifdef CLONE_NEWUSER + if (unshare (CLONE_NEWUSER | CLONE_NEWNS) == 0) + /* Even if we do not have UID zero, we have extended privileges at + this point. */ + return true; #endif + if (setuid (0) != 0) + { + printf ("warning: could not become root outside namespace (%m)\n"); + return false; + } + return true; +} diff --git a/support/support_can_chroot.c b/support/support_can_chroot.c new file mode 100644 index 0000000000..0dfd2deb54 --- /dev/null +++ b/support/support_can_chroot.c @@ -0,0 +1,65 @@ +/* Return true if the process can perform a chroot operation. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static void +callback (void *closure) +{ + int *result = closure; + struct stat64 before; + xstat ("/dev", &before); + if (chroot ("/dev") != 0) + { + *result = errno; + return; + } + struct stat64 after; + xstat ("/", &after); + TEST_VERIFY (before.st_dev == after.st_dev); + TEST_VERIFY (before.st_ino == after.st_ino); + *result = 0; +} + +bool +support_can_chroot (void) +{ + int *result = support_shared_allocate (sizeof (*result)); + *result = 0; + support_isolate_in_subprocess (callback, result); + bool ok = *result == 0; + if (!ok) + { + static bool already_warned; + if (!already_warned) + { + already_warned = true; + errno = *result; + printf ("warning: this process does not support chroot: %m\n"); + } + } + support_shared_free (result); + return ok; +} diff --git a/support/support_capture_subprocess.c b/support/support_capture_subprocess.c new file mode 100644 index 0000000000..030f124252 --- /dev/null +++ b/support/support_capture_subprocess.c @@ -0,0 +1,108 @@ +/* Capture output from a subprocess. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include +#include +#include + +static void +transfer (const char *what, struct pollfd *pfd, struct xmemstream *stream) +{ + if (pfd->revents != 0) + { + char buf[1024]; + ssize_t ret = TEMP_FAILURE_RETRY (read (pfd->fd, buf, sizeof (buf))); + if (ret < 0) + { + support_record_failure (); + printf ("error: reading from subprocess %s: %m", what); + pfd->events = 0; + pfd->revents = 0; + } + else if (ret == 0) + { + /* EOF reached. Stop listening. */ + pfd->events = 0; + pfd->revents = 0; + } + else + /* Store the data just read. */ + TEST_VERIFY (fwrite (buf, ret, 1, stream->out) == 1); + } +} + +struct support_capture_subprocess +support_capture_subprocess (void (*callback) (void *), void *closure) +{ + struct support_capture_subprocess result; + xopen_memstream (&result.out); + xopen_memstream (&result.err); + + int stdout_pipe[2]; + xpipe (stdout_pipe); + int stderr_pipe[2]; + xpipe (stderr_pipe); + + TEST_VERIFY (fflush (stdout) == 0); + TEST_VERIFY (fflush (stderr) == 0); + + pid_t pid = xfork (); + if (pid == 0) + { + xclose (stdout_pipe[0]); + xclose (stderr_pipe[0]); + xdup2 (stdout_pipe[1], STDOUT_FILENO); + xdup2 (stderr_pipe[1], STDERR_FILENO); + callback (closure); + _exit (0); + } + xclose (stdout_pipe[1]); + xclose (stderr_pipe[1]); + + struct pollfd fds[2] = + { + { .fd = stdout_pipe[0], .events = POLLIN }, + { .fd = stderr_pipe[0], .events = POLLIN }, + }; + + do + { + xpoll (fds, 2, -1); + transfer ("stdout", &fds[0], &result.out); + transfer ("stderr", &fds[1], &result.err); + } + while (fds[0].events != 0 || fds[1].events != 0); + xclose (stdout_pipe[0]); + xclose (stderr_pipe[0]); + + xfclose_memstream (&result.out); + xfclose_memstream (&result.err); + xwaitpid (pid, &result.status, 0); + return result; +} + +void +support_capture_subprocess_free (struct support_capture_subprocess *p) +{ + free (p->out.buffer); + free (p->err.buffer); +} diff --git a/support/support_capture_subprocess_check.c b/support/support_capture_subprocess_check.c new file mode 100644 index 0000000000..708c89f331 --- /dev/null +++ b/support/support_capture_subprocess_check.c @@ -0,0 +1,67 @@ +/* Verify capture output from a subprocess. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include + +static void +print_context (const char *context, bool *failed) +{ + if (*failed) + /* Do not duplicate message. */ + return; + support_record_failure (); + printf ("error: subprocess failed: %s\n", context); +} + +void +support_capture_subprocess_check (struct support_capture_subprocess *proc, + const char *context, int status, + int allowed) +{ + TEST_VERIFY ((allowed & sc_allow_none) + || (allowed & sc_allow_stdout) + || (allowed & sc_allow_stderr)); + TEST_VERIFY (!((allowed & sc_allow_none) + && ((allowed & sc_allow_stdout) + || (allowed & sc_allow_stderr)))); + + bool failed = false; + if (proc->status != status) + { + print_context (context, &failed); + printf ("error: expected exit status: %d\n", status); + printf ("error: actual exit status: %d\n", status); + } + if (!(allowed & sc_allow_stdout) && proc->out.length != 0) + { + print_context (context, &failed); + printf ("error: unexpected output from subprocess\n"); + fwrite (proc->out.buffer, proc->out.length, 1, stdout); + puts ("\n"); + } + if (!(allowed & sc_allow_stderr) && proc->err.length != 0) + { + print_context (context, &failed); + printf ("error: unexpected error output from subprocess\n"); + fwrite (proc->err.buffer, proc->err.length, 1, stdout); + puts ("\n"); + } +} diff --git a/support/support_enter_network_namespace.c b/support/support_enter_network_namespace.c new file mode 100644 index 0000000000..28b0ee29cf --- /dev/null +++ b/support/support_enter_network_namespace.c @@ -0,0 +1,75 @@ +/* Enter a network namespace. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static bool in_uts_namespace; + +bool +support_enter_network_namespace (void) +{ +#ifdef CLONE_NEWUTS + if (unshare (CLONE_NEWUTS) == 0) + in_uts_namespace = true; + else + printf ("warning: unshare (CLONE_NEWUTS) failed: %m\n"); +#endif + +#ifdef CLONE_NEWNET + if (unshare (CLONE_NEWNET) == 0) + { + /* Bring up the loopback interface. */ + int fd = xsocket (AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0); + struct ifreq req; + strcpy (req.ifr_name, "lo"); + TEST_VERIFY_EXIT (ioctl (fd, SIOCGIFFLAGS, &req) == 0); + bool already_up = req.ifr_flags & IFF_UP; + if (already_up) + /* This means that we likely have not achieved isolation from + the parent namespace. */ + printf ("warning: loopback interface already exists" + " in new network namespace\n"); + else + { + req.ifr_flags |= IFF_UP | IFF_RUNNING; + TEST_VERIFY_EXIT (ioctl (fd, SIOCSIFFLAGS, &req) == 0); + } + xclose (fd); + + return !already_up; + } +#endif + printf ("warning: could not enter network namespace\n"); + return false; +} + +bool +support_in_uts_namespace (void) +{ + return in_uts_namespace; +} diff --git a/sysdeps/sparc/sparc32/sparcv9/fpu/s_fdimf.S b/support/support_format_address_family.c similarity index 63% rename from sysdeps/sparc/sparc32/sparcv9/fpu/s_fdimf.S rename to support/support_format_address_family.c index 9e0e3f21be..5d42c42a45 100644 --- a/sysdeps/sparc/sparc32/sparcv9/fpu/s_fdimf.S +++ b/support/support_format_address_family.c @@ -1,7 +1,6 @@ -/* Compute positive difference, sparc 32-bit+v9. - Copyright (C) 2013-2016 Free Software Foundation, Inc. +/* Convert an address family to a string. + Copyright (C) 2016-2017 Free Software Foundation, Inc. This file is part of the GNU C Library. - Contributed by David S. Miller . The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -17,19 +16,20 @@ License along with the GNU C Library; if not, see . */ -#include +#include -ENTRY(__fdimf) - st %o0, [%sp + 72] - st %o1, [%sp + 76] - ld [%sp + 72], %f0 - ld [%sp + 76], %f1 - fcmps %f0, %f1 - fbug 1f - nop - fzeros %f0 - fnegs %f0, %f1 -1: retl - fsubs %f0, %f1, %f0 -END(__fdimf) -weak_alias (__fdimf, fdimf) +#include + +char * +support_format_address_family (int family) +{ + switch (family) + { + case AF_INET: + return xstrdup ("INET"); + case AF_INET6: + return xstrdup ("INET6"); + default: + return xasprintf ("", family); + } +} diff --git a/support/support_format_addrinfo.c b/support/support_format_addrinfo.c new file mode 100644 index 0000000000..eedb030591 --- /dev/null +++ b/support/support_format_addrinfo.c @@ -0,0 +1,239 @@ +/* Convert struct addrinfo values to a string. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include +#include +#include + +static size_t +socket_address_length (int family) +{ + switch (family) + { + case AF_INET: + return sizeof (struct sockaddr_in); + case AF_INET6: + return sizeof (struct sockaddr_in6); + default: + return -1; + } +} + +static void +format_ai_flags_1 (FILE *out, struct addrinfo *ai, int flag, const char *name, + int * flags_printed) +{ + if ((ai->ai_flags & flag) != 0) + fprintf (out, " %s", name); + *flags_printed |= flag; +} + +static void +format_ai_flags (FILE *out, struct addrinfo *ai) +{ + if (ai == NULL) + return; + + if (ai->ai_flags != 0) + { + fprintf (out, "flags:"); + int flags_printed = 0; +#define FLAG(flag) format_ai_flags_1 (out, ai, flag, #flag, &flags_printed) + FLAG (AI_PASSIVE); + FLAG (AI_CANONNAME); + FLAG (AI_NUMERICHOST); + FLAG (AI_V4MAPPED); + FLAG (AI_ALL); + FLAG (AI_ADDRCONFIG); + FLAG (AI_IDN); + FLAG (AI_CANONIDN); + FLAG (AI_IDN_ALLOW_UNASSIGNED); + FLAG (AI_IDN_USE_STD3_ASCII_RULES); + FLAG (AI_NUMERICSERV); +#undef FLAG + int remaining = ai->ai_flags & ~flags_printed; + if (remaining != 0) + fprintf (out, " %08x", remaining); + fprintf (out, "\n"); + } + + /* Report flag mismatches within the list. */ + int flags = ai->ai_flags; + int index = 1; + ai = ai->ai_next; + while (ai != NULL) + { + if (ai->ai_flags != flags) + fprintf (out, "error: flags at %d: 0x%x expected, 0x%x actual\n", + index, flags, ai->ai_flags); + ai = ai->ai_next; + ++index; + } +} + +static void +format_ai_canonname (FILE *out, struct addrinfo *ai) +{ + if (ai == NULL) + return; + if (ai->ai_canonname != NULL) + fprintf (out, "canonname: %s\n", ai->ai_canonname); + + /* Report incorrectly set ai_canonname fields on subsequent list + entries. */ + int index = 1; + ai = ai->ai_next; + while (ai != NULL) + { + if (ai->ai_canonname != NULL) + fprintf (out, "error: canonname set at %d: %s\n", + index, ai->ai_canonname); + ai = ai->ai_next; + ++index; + } +} + +static void +format_ai_one (FILE *out, struct addrinfo *ai) +{ + { + char type_buf[32]; + const char *type_str; + char proto_buf[32]; + const char *proto_str; + + /* ai_socktype */ + switch (ai->ai_socktype) + { + case SOCK_RAW: + type_str = "RAW"; + break; + case SOCK_DGRAM: + type_str = "DGRAM"; + break; + case SOCK_STREAM: + type_str = "STREAM"; + break; + default: + snprintf (type_buf, sizeof (type_buf), "%d", ai->ai_socktype); + type_str = type_buf; + } + + /* ai_protocol */ + switch (ai->ai_protocol) + { + case IPPROTO_IP: + proto_str = "IP"; + break; + case IPPROTO_UDP: + proto_str = "UDP"; + break; + case IPPROTO_TCP: + proto_str = "TCP"; + break; + default: + snprintf (proto_buf, sizeof (proto_buf), "%d", ai->ai_protocol); + proto_str = proto_buf; + } + fprintf (out, "address: %s/%s", type_str, proto_str); + } + + /* ai_addrlen */ + if (ai->ai_addrlen != socket_address_length (ai->ai_family)) + { + char *family = support_format_address_family (ai->ai_family); + fprintf (out, "error: invalid address length %d for %s\n", + ai->ai_addrlen, family); + free (family); + } + + /* ai_addr */ + { + char buf[128]; + uint16_t port; + const char *ret; + switch (ai->ai_family) + { + case AF_INET: + { + struct sockaddr_in *sin = (struct sockaddr_in *) ai->ai_addr; + ret = inet_ntop (AF_INET, &sin->sin_addr, buf, sizeof (buf)); + port = sin->sin_port; + } + break; + case AF_INET6: + { + struct sockaddr_in6 *sin = (struct sockaddr_in6 *) ai->ai_addr; + ret = inet_ntop (AF_INET6, &sin->sin6_addr, buf, sizeof (buf)); + port = sin->sin6_port; + } + break; + default: + errno = EAFNOSUPPORT; + ret = NULL; + } + if (ret == NULL) + fprintf (out, "error: inet_top failed: %m\n"); + else + fprintf (out, " %s %u\n", buf, ntohs (port)); + } +} + +/* Format all the addresses in one address family. */ +static void +format_ai_family (FILE *out, struct addrinfo *ai, int family) +{ + while (ai) + { + if (ai->ai_family == family) + format_ai_one (out, ai); + ai = ai->ai_next; + } +} + +char * +support_format_addrinfo (struct addrinfo *ai, int ret) +{ + int errno_copy = errno; + + struct xmemstream mem; + xopen_memstream (&mem); + if (ret != 0) + { + fprintf (mem.out, "error: %s\n", gai_strerror (ret)); + if (ret == EAI_SYSTEM) + { + errno = errno_copy; + fprintf (mem.out, "error: %m\n"); + } + } + else + { + format_ai_flags (mem.out, ai); + format_ai_canonname (mem.out, ai); + format_ai_family (mem.out, ai, AF_INET); + format_ai_family (mem.out, ai, AF_INET6); + } + + xfclose_memstream (&mem); + return mem.buffer; +} diff --git a/support/support_format_dns_packet.c b/support/support_format_dns_packet.c new file mode 100644 index 0000000000..2992c57971 --- /dev/null +++ b/support/support_format_dns_packet.c @@ -0,0 +1,222 @@ +/* Convert a DNS packet to a human-readable representation. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include +#include +#include + +struct in_buffer +{ + const unsigned char *data; + size_t size; +}; + +static inline bool +extract_8 (struct in_buffer *in, unsigned char *value) +{ + if (in->size == 0) + return false; + *value = in->data[0]; + ++in->data; + --in->size; + return true; +} + +static inline bool +extract_16 (struct in_buffer *in, unsigned short *value) +{ + if (in->size < 2) + return false; + *value = (in->data[0] << 8) | in->data[1]; + in->data += 2; + in->size -= 2; + return true; +} + +static inline bool +extract_32 (struct in_buffer *in, unsigned *value) +{ + if (in->size < 4) + return false; + unsigned a = in->data[0]; + unsigned b = in->data[1]; + unsigned c = in->data[2]; + unsigned d = in->data[3]; + *value = (a << 24) | (b << 16) | (c << 8) | d; + in->data += 4; + in->size -= 4; + return true; +} + +static inline bool +extract_bytes (struct in_buffer *in, size_t length, struct in_buffer *value) +{ + if (in->size < length) + return false; + *value = (struct in_buffer) {in->data, length}; + in->data += length; + in->size -= length; + return true; +} + +struct dname +{ + char name[MAXDNAME + 1]; +}; + +static bool +extract_name (struct in_buffer full, struct in_buffer *in, struct dname *value) +{ + const unsigned char *full_end = full.data + full.size; + /* Sanity checks; these indicate buffer misuse. */ + TEST_VERIFY_EXIT + (!(in->data < full.data || in->data > full_end + || in->size > (size_t) (full_end - in->data))); + int ret = dn_expand (full.data, full_end, in->data, + value->name, sizeof (value->name)); + if (ret < 0) + return false; + in->data += ret; + in->size -= ret; + return true; +} + +char * +support_format_dns_packet (const unsigned char *buffer, size_t length) +{ + struct in_buffer full = { buffer, length }; + struct in_buffer in = full; + struct xmemstream mem; + xopen_memstream (&mem); + + unsigned short txnid; + unsigned short flags; + unsigned short qdcount; + unsigned short ancount; + unsigned short nscount; + unsigned short adcount; + if (!(extract_16 (&in, &txnid) + && extract_16 (&in, &flags) + && extract_16 (&in, &qdcount) + && extract_16 (&in, &ancount) + && extract_16 (&in, &nscount) + && extract_16 (&in, &adcount))) + { + fprintf (mem.out, "error: could not parse DNS header\n"); + goto out; + } + if (qdcount != 1) + { + fprintf (mem.out, "error: question count is %d, not 1\n", qdcount); + goto out; + } + struct dname qname; + if (!extract_name (full, &in, &qname)) + { + fprintf (mem.out, "error: malformed QNAME\n"); + goto out; + } + unsigned short qtype; + unsigned short qclass; + if (!(extract_16 (&in, &qtype) + && extract_16 (&in, &qclass))) + { + fprintf (mem.out, "error: malformed question\n"); + goto out; + } + if (qtype != T_A && qtype != T_AAAA && qtype != T_PTR) + { + fprintf (mem.out, "error: unsupported QTYPE %d\n", qtype); + goto out; + } + + fprintf (mem.out, "name: %s\n", qname.name); + + for (int i = 0; i < ancount; ++i) + { + struct dname rname; + if (!extract_name (full, &in, &rname)) + { + fprintf (mem.out, "error: malformed record name\n"); + goto out; + } + unsigned short rtype; + unsigned short rclass; + unsigned ttl; + unsigned short rdlen; + struct in_buffer rdata; + if (!(extract_16 (&in, &rtype) + && extract_16 (&in, &rclass) + && extract_32 (&in, &ttl) + && extract_16 (&in, &rdlen) + && extract_bytes (&in, rdlen, &rdata))) + { + fprintf (mem.out, "error: malformed record header\n"); + goto out; + } + /* Skip non-matching record types. */ + if ((rtype != qtype && rtype != T_CNAME) || rclass != qclass) + continue; + switch (rtype) + { + case T_A: + if (rdlen == 4) + fprintf (mem.out, "address: %d.%d.%d.%d\n", + rdata.data[0], + rdata.data[1], + rdata.data[2], + rdata.data[3]); + else + fprintf (mem.out, "error: A record of size %d: %s\n", + rdlen, rname.name); + break; + case T_AAAA: + { + if (rdlen == 16) + { + char buf[100]; + if (inet_ntop (AF_INET6, rdata.data, buf, sizeof (buf)) == NULL) + fprintf (mem.out, "error: AAAA record decoding failed: %m\n"); + else + fprintf (mem.out, "address: %s\n", buf); + } + else + fprintf (mem.out, "error: AAAA record of size %d: %s\n", + rdlen, rname.name); + } + break; + case T_CNAME: + case T_PTR: + { + struct dname name; + if (extract_name (full, &rdata, &name)) + fprintf (mem.out, "name: %s\n", name.name); + else + fprintf (mem.out, "error: malformed CNAME/PTR record\n"); + } + } + } + + out: + xfclose_memstream (&mem); + return mem.buffer; +} diff --git a/support/support_format_herrno.c b/support/support_format_herrno.c new file mode 100644 index 0000000000..493d6ae962 --- /dev/null +++ b/support/support_format_herrno.c @@ -0,0 +1,45 @@ +/* Convert a h_errno error code to a string. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include + +char * +support_format_herrno (int code) +{ + const char *errstr; + switch (code) + { + case HOST_NOT_FOUND: + errstr = "HOST_NOT_FOUND"; + break; + case NO_ADDRESS: + errstr = "NO_ADDRESS"; + break; + case NO_RECOVERY: + errstr = "NO_RECOVERY"; + break; + case TRY_AGAIN: + errstr = "TRY_AGAIN"; + break; + default: + return xasprintf ("\n", code); + } + return xstrdup (errstr); +} diff --git a/support/support_format_hostent.c b/support/support_format_hostent.c new file mode 100644 index 0000000000..5b5f26082e --- /dev/null +++ b/support/support_format_hostent.c @@ -0,0 +1,75 @@ +/* Convert a struct hostent object to a string. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include +#include + +static int +address_length (int family) +{ + switch (family) + { + case AF_INET: + return 4; + case AF_INET6: + return 16; + } + return -1; +} + +char * +support_format_hostent (struct hostent *h) +{ + if (h == NULL) + { + char *value = support_format_herrno (h_errno); + char *result = xasprintf ("error: %s\n", value); + free (value); + return result; + } + + struct xmemstream mem; + xopen_memstream (&mem); + + fprintf (mem.out, "name: %s\n", h->h_name); + for (char **alias = h->h_aliases; *alias != NULL; ++alias) + fprintf (mem.out, "alias: %s\n", *alias); + for (unsigned i = 0; h->h_addr_list[i] != NULL; ++i) + { + char buf[128]; + if (inet_ntop (h->h_addrtype, h->h_addr_list[i], + buf, sizeof (buf)) == NULL) + fprintf (mem.out, "error: inet_ntop failed: %m\n"); + else + fprintf (mem.out, "address: %s\n", buf); + } + if (h->h_length != address_length (h->h_addrtype)) + { + char *family = support_format_address_family (h->h_addrtype); + fprintf (mem.out, "error: invalid address length %d for %s\n", + h->h_length, family); + free (family); + } + + xfclose_memstream (&mem); + return mem.buffer; +} diff --git a/support/support_format_netent.c b/support/support_format_netent.c new file mode 100644 index 0000000000..020f5720d9 --- /dev/null +++ b/support/support_format_netent.c @@ -0,0 +1,52 @@ +/* Convert a struct netent object to a string. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include +#include + +char * +support_format_netent (struct netent *e) +{ + if (e == NULL) + { + char *value = support_format_herrno (h_errno); + char *result = xasprintf ("error: %s\n", value); + free (value); + return result; + } + + struct xmemstream mem; + xopen_memstream (&mem); + + if (e->n_name != NULL) + fprintf (mem.out, "name: %s\n", e->n_name); + for (char **ap = e->n_aliases; *ap != NULL; ++ap) + fprintf (mem.out, "alias: %s\n", *ap); + if (e->n_addrtype != AF_INET) + fprintf (mem.out, "addrtype: %d\n", e->n_addrtype); + /* On alpha, e->n_net is an unsigned long. */ + unsigned int n_net = e->n_net; + fprintf (mem.out, "net: 0x%08x\n", n_net); + + xfclose_memstream (&mem); + return mem.buffer; +} diff --git a/support/support_isolate_in_subprocess.c b/support/support_isolate_in_subprocess.c new file mode 100644 index 0000000000..cf48614383 --- /dev/null +++ b/support/support_isolate_in_subprocess.c @@ -0,0 +1,38 @@ +/* Run a function in a subprocess. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include + +void +support_isolate_in_subprocess (void (*callback) (void *), void *closure) +{ + pid_t pid = xfork (); + if (pid == 0) + { + /* Child process. */ + callback (closure); + _exit (0); + } + + /* Parent process. */ + int status; + xwaitpid (pid, &status, 0); + if (status != 0) + FAIL_EXIT1 ("child process exited with status %d", status); +} diff --git a/support/support_record_failure.c b/support/support_record_failure.c new file mode 100644 index 0000000000..684055c746 --- /dev/null +++ b/support/support_record_failure.c @@ -0,0 +1,106 @@ +/* Global test failure counter. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +/* This structure keeps track of test failures. The counter is + incremented on each failure. The failed member is set to true if a + failure is detected, so that even if the counter wraps around to + zero, the failure of a test can be detected. + + The init constructor function below puts *state on a shared + annonymous mapping, so that failure reports from subprocesses + propagate to the parent process. */ +struct test_failures +{ + unsigned int counter; + unsigned int failed; +}; +static struct test_failures *state; + +static __attribute__ ((constructor)) void +init (void) +{ + void *ptr = mmap (NULL, sizeof (*state), PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_SHARED, -1, 0); + if (ptr == MAP_FAILED) + { + printf ("error: could not map %zu bytes: %m\n", sizeof (*state)); + exit (1); + } + /* Zero-initialization of the struct is sufficient. */ + state = ptr; +} + +void +support_record_failure (void) +{ + if (state == NULL) + { + write_message + ("error: support_record_failure called without initialization\n"); + _exit (1); + } + /* Relaxed MO is sufficient because we are only interested in the + values themselves, in isolation. */ + __atomic_store_n (&state->failed, 1, __ATOMIC_RELEASE); + __atomic_add_fetch (&state->counter, 1, __ATOMIC_RELEASE); +} + +int +support_report_failure (int status) +{ + if (state == NULL) + { + write_message + ("error: support_report_failure called without initialization\n"); + return 1; + } + + /* Relaxed MO is sufficient because acquire test result reporting + assumes that exiting from the main thread happens before the + error reporting via support_record_failure, which requires some + form of external synchronization. */ + bool failed = __atomic_load_n (&state->failed, __ATOMIC_RELAXED); + if (failed) + printf ("error: %u test failures\n", + __atomic_load_n (&state->counter, __ATOMIC_RELAXED)); + + if ((status == 0 || status == EXIT_UNSUPPORTED) && failed) + /* If we have a recorded failure, it overrides a non-failure + report from the test function. */ + status = 1; + return status; +} + +void +support_record_failure_reset (void) +{ + /* Only used for testing the test framework, with external + synchronization, but use release MO for consistency. */ + __atomic_store_n (&state->failed, 0, __ATOMIC_RELAXED); + __atomic_add_fetch (&state->counter, 0, __ATOMIC_RELAXED); +} diff --git a/support/support_run_diff.c b/support/support_run_diff.c new file mode 100644 index 0000000000..f5155de727 --- /dev/null +++ b/support/support_run_diff.c @@ -0,0 +1,76 @@ +/* Invoke the system diff tool to compare two strings. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +static char * +write_to_temp_file (const char *prefix, const char *str) +{ + char *template = xasprintf ("run_diff-%s", prefix); + char *name = NULL; + int fd = create_temp_file (template, &name); + TEST_VERIFY_EXIT (fd >= 0); + free (template); + xwrite (fd, str, strlen (str)); + xclose (fd); + return name; +} + +void +support_run_diff (const char *left_label, const char *left, + const char *right_label, const char *right) +{ + /* Ensure that the diff command output is ordered properly with + standard output. */ + TEST_VERIFY_EXIT (fflush (stdout) == 0); + + char *left_path = write_to_temp_file ("left-diff", left); + char *right_path = write_to_temp_file ("right-diff", right); + + pid_t pid = xfork (); + if (pid == 0) + { + execlp ("diff", "diff", "-u", + "--label", left_label, "--label", right_label, + "--", left_path, right_path, + NULL); + _exit (17); + } + else + { + int status; + xwaitpid (pid, &status, 0); + if (!WIFEXITED (status) || WEXITSTATUS (status) != 1) + printf ("warning: could not run diff, exit status: %d\n" + "*** %s ***\n%s\n" + "*** %s ***\n%s\n", + status, left_label, left, right_label, right); + } + + free (right_path); + free (left_path); +} diff --git a/support/support_shared_allocate.c b/support/support_shared_allocate.c new file mode 100644 index 0000000000..61d088e8cf --- /dev/null +++ b/support/support_shared_allocate.c @@ -0,0 +1,57 @@ +/* Allocate a memory region shared across processes. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include + +/* Header for the allocation. It contains the size of the allocation + for subsequent unmapping. */ +struct header +{ + size_t total_size; + char data[] __attribute__ ((aligned (__alignof__ (max_align_t)))); +}; + +void * +support_shared_allocate (size_t size) +{ + size_t total_size = size + offsetof (struct header, data); + if (total_size < size) + { + errno = ENOMEM; + oom_error (__func__, size); + return NULL; + } + else + { + struct header *result = xmmap (NULL, total_size, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_SHARED, -1); + result->total_size = total_size; + return &result->data; + } +} + +void +support_shared_free (void *data) +{ + struct header *header = data - offsetof (struct header, data); + xmunmap (header, header->total_size); +} diff --git a/support/support_test_main.c b/support/support_test_main.c new file mode 100644 index 0000000000..914d64f603 --- /dev/null +++ b/support/support_test_main.c @@ -0,0 +1,423 @@ +/* Main worker function for the test driver. + Copyright (C) 1998-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const struct option default_options[] = +{ + TEST_DEFAULT_OPTIONS + { NULL, 0, NULL, 0 } +}; + +/* Show people how to run the program. */ +static void +usage (const struct option *options) +{ + size_t i; + + printf ("Usage: %s [options]\n" + "\n" + "Environment Variables:\n" + " TIMEOUTFACTOR An integer used to scale the timeout\n" + " TMPDIR Where to place temporary files\n" + " TEST_COREDUMPS Do not disable coredumps if set\n" + "\n", + program_invocation_short_name); + printf ("Options:\n"); + for (i = 0; options[i].name; ++i) + { + int indent; + + indent = printf (" --%s", options[i].name); + if (options[i].has_arg == required_argument) + indent += printf (" "); + printf ("%*s", 25 - indent, ""); + switch (options[i].val) + { + case 'v': + printf ("Increase the output verbosity"); + break; + case OPT_DIRECT: + printf ("Run the test directly (instead of forking & monitoring)"); + break; + case OPT_TESTDIR: + printf ("Override the TMPDIR env var"); + break; + } + printf ("\n"); + } +} + +/* The PID of the test process. */ +static pid_t test_pid; + +/* The cleanup handler passed to test_main. */ +static void (*cleanup_function) (void); + +/* Timeout handler. We kill the child and exit with an error. */ +static void +__attribute__ ((noreturn)) +signal_handler (int sig) +{ + int killed; + int status; + + assert (test_pid > 1); + /* Kill the whole process group. */ + kill (-test_pid, SIGKILL); + /* In case setpgid failed in the child, kill it individually too. */ + kill (test_pid, SIGKILL); + + /* Wait for it to terminate. */ + int i; + for (i = 0; i < 5; ++i) + { + killed = waitpid (test_pid, &status, WNOHANG|WUNTRACED); + if (killed != 0) + break; + + /* Delay, give the system time to process the kill. If the + nanosleep() call return prematurely, all the better. We + won't restart it since this probably means the child process + finally died. */ + struct timespec ts; + ts.tv_sec = 0; + ts.tv_nsec = 100000000; + nanosleep (&ts, NULL); + } + if (killed != 0 && killed != test_pid) + { + printf ("Failed to kill test process: %m\n"); + exit (1); + } + + if (cleanup_function != NULL) + cleanup_function (); + + if (sig == SIGINT) + { + signal (sig, SIG_DFL); + raise (sig); + } + + if (killed == 0 || (WIFSIGNALED (status) && WTERMSIG (status) == SIGKILL)) + puts ("Timed out: killed the child process"); + else if (WIFSTOPPED (status)) + printf ("Timed out: the child process was %s\n", + strsignal (WSTOPSIG (status))); + else if (WIFSIGNALED (status)) + printf ("Timed out: the child process got signal %s\n", + strsignal (WTERMSIG (status))); + else + printf ("Timed out: killed the child process but it exited %d\n", + WEXITSTATUS (status)); + + /* Exit with an error. */ + exit (1); +} + +/* Run test_function or test_function_argv. */ +static int +run_test_function (int argc, char **argv, const struct test_config *config) +{ + if (config->test_function != NULL) + return config->test_function (); + else if (config->test_function_argv != NULL) + return config->test_function_argv (argc, argv); + else + { + printf ("error: no test function defined\n"); + exit (1); + } +} + +static bool test_main_called; + +const char *test_dir = NULL; +unsigned int test_verbose = 0; + +/* If test failure reporting has been linked in, it may contribute + additional test failures. */ +static int +adjust_exit_status (int status) +{ + if (support_report_failure != NULL) + return support_report_failure (status); + return status; +} + +int +support_test_main (int argc, char **argv, const struct test_config *config) +{ + if (test_main_called) + { + printf ("error: test_main called for a second time\n"); + exit (1); + } + test_main_called = true; + const struct option *options; + if (config->options != NULL) + options = config->options; + else + options = default_options; + + cleanup_function = config->cleanup_function; + + int direct = 0; /* Directly call the test function? */ + int status; + int opt; + unsigned int timeoutfactor = 1; + pid_t termpid; + + if (!config->no_mallopt) + { + /* Make uses of freed and uninitialized memory known. Do not + pull in a definition for mallopt if it has not been defined + already. */ + extern __typeof__ (mallopt) mallopt __attribute__ ((weak)); + if (mallopt != NULL) + mallopt (M_PERTURB, 42); + } + + while ((opt = getopt_long (argc, argv, "+", options, NULL)) != -1) + switch (opt) + { + case '?': + usage (options); + exit (1); + case 'v': + ++test_verbose; + break; + case OPT_DIRECT: + direct = 1; + break; + case OPT_TESTDIR: + test_dir = optarg; + break; + default: + if (config->cmdline_function != NULL) + config->cmdline_function (opt); + } + + /* If set, read the test TIMEOUTFACTOR value from the environment. + This value is used to scale the default test timeout values. */ + char *envstr_timeoutfactor = getenv ("TIMEOUTFACTOR"); + if (envstr_timeoutfactor != NULL) + { + char *envstr_conv = envstr_timeoutfactor; + unsigned long int env_fact; + + env_fact = strtoul (envstr_timeoutfactor, &envstr_conv, 0); + if (*envstr_conv == '\0' && envstr_conv != envstr_timeoutfactor) + timeoutfactor = MAX (env_fact, 1); + } + + /* Set TMPDIR to specified test directory. */ + if (test_dir != NULL) + { + setenv ("TMPDIR", test_dir, 1); + + if (chdir (test_dir) < 0) + { + printf ("chdir: %m\n"); + exit (1); + } + } + else + { + test_dir = getenv ("TMPDIR"); + if (test_dir == NULL || test_dir[0] == '\0') + test_dir = "/tmp"; + } + if (support_set_test_dir != NULL) + support_set_test_dir (test_dir); + + int timeout = config->timeout; + if (timeout == 0) + timeout = DEFAULT_TIMEOUT; + + /* Make sure we see all message, even those on stdout. */ + setvbuf (stdout, NULL, _IONBF, 0); + + /* Make sure temporary files are deleted. */ + if (support_delete_temp_files != NULL) + atexit (support_delete_temp_files); + + /* Correct for the possible parameters. */ + argv[optind - 1] = argv[0]; + argv += optind - 1; + argc -= optind - 1; + + /* Call the initializing function, if one is available. */ + if (config->prepare_function != NULL) + config->prepare_function (argc, argv); + + const char *envstr_direct = getenv ("TEST_DIRECT"); + if (envstr_direct != NULL) + { + FILE *f = fopen (envstr_direct, "w"); + if (f == NULL) + { + printf ("cannot open TEST_DIRECT output file '%s': %m\n", + envstr_direct); + exit (1); + } + + fprintf (f, "timeout=%u\ntimeoutfactor=%u\n", + config->timeout, timeoutfactor); + if (config->expected_status != 0) + fprintf (f, "exit=%u\n", config->expected_status); + if (config->expected_signal != 0) + fprintf (f, "signal=%s\n", strsignal (config->expected_signal)); + + if (support_print_temp_files != NULL) + support_print_temp_files (f); + + fclose (f); + direct = 1; + } + + bool disable_coredumps; + { + const char *coredumps = getenv ("TEST_COREDUMPS"); + disable_coredumps = coredumps == NULL || coredumps[0] == '\0'; + } + + /* If we are not expected to fork run the function immediately. */ + if (direct) + return adjust_exit_status (run_test_function (argc, argv, config)); + + /* Set up the test environment: + - prevent core dumps + - set up the timer + - fork and execute the function. */ + + test_pid = fork (); + if (test_pid == 0) + { + /* This is the child. */ + if (disable_coredumps) + { + /* Try to avoid dumping core. This is necessary because we + run the test from the source tree, and the coredumps + would end up there (and not in the build tree). */ + struct rlimit core_limit; + core_limit.rlim_cur = 0; + core_limit.rlim_max = 0; + setrlimit (RLIMIT_CORE, &core_limit); + } + + /* We put the test process in its own pgrp so that if it bogusly + generates any job control signals, they won't hit the whole build. */ + if (setpgid (0, 0) != 0) + printf ("Failed to set the process group ID: %m\n"); + + /* Execute the test function and exit with the return value. */ + exit (run_test_function (argc, argv, config)); + } + else if (test_pid < 0) + { + printf ("Cannot fork test program: %m\n"); + exit (1); + } + + /* Set timeout. */ + signal (SIGALRM, signal_handler); + alarm (timeout * timeoutfactor); + + /* Make sure we clean up if the wrapper gets interrupted. */ + signal (SIGINT, signal_handler); + + /* Wait for the regular termination. */ + termpid = TEMP_FAILURE_RETRY (waitpid (test_pid, &status, 0)); + if (termpid == -1) + { + printf ("Waiting for test program failed: %m\n"); + exit (1); + } + if (termpid != test_pid) + { + printf ("Oops, wrong test program terminated: expected %ld, got %ld\n", + (long int) test_pid, (long int) termpid); + exit (1); + } + + /* Process terminated normaly without timeout etc. */ + if (WIFEXITED (status)) + { + if (config->expected_status == 0) + { + if (config->expected_signal == 0) + /* Exit with the return value of the test. */ + return adjust_exit_status (WEXITSTATUS (status)); + else + { + printf ("Expected signal '%s' from child, got none\n", + strsignal (config->expected_signal)); + exit (1); + } + } + else + { + /* Non-zero exit status is expected */ + if (WEXITSTATUS (status) != config->expected_status) + { + printf ("Expected status %d, got %d\n", + config->expected_status, WEXITSTATUS (status)); + exit (1); + } + } + return adjust_exit_status (0); + } + /* Process was killed by timer or other signal. */ + else + { + if (config->expected_signal == 0) + { + printf ("Didn't expect signal from child: got `%s'\n", + strsignal (WTERMSIG (status))); + exit (1); + } + else if (WTERMSIG (status) != config->expected_signal) + { + printf ("Incorrect signal from child: got `%s', need `%s'\n", + strsignal (WTERMSIG (status)), + strsignal (config->expected_signal)); + exit (1); + } + + return adjust_exit_status (0); + } +} diff --git a/support/support_test_verify_impl.c b/support/support_test_verify_impl.c new file mode 100644 index 0000000000..5bae38f8b1 --- /dev/null +++ b/support/support_test_verify_impl.c @@ -0,0 +1,33 @@ +/* Implementation of the TEST_VERIFY and TEST_VERIFY_EXIT macros. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include + +void +support_test_verify_impl (int status, const char *file, int line, + const char *expr) +{ + support_record_failure (); + printf ("error: %s:%d: not true: %s\n", file, line, expr); + if (status >= 0) + exit (status); + +} diff --git a/support/support_write_file_string.c b/support/support_write_file_string.c new file mode 100644 index 0000000000..48e89597f3 --- /dev/null +++ b/support/support_write_file_string.c @@ -0,0 +1,39 @@ +/* Write a string to a file. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include + +void +support_write_file_string (const char *path, const char *contents) +{ + int fd = xopen (path, O_CREAT | O_TRUNC | O_WRONLY, 0666); + const char *end = contents + strlen (contents); + for (const char *p = contents; p < end; ) + { + ssize_t ret = write (fd, p, end - p); + if (ret < 0) + FAIL_EXIT1 ("cannot write to \"%s\": %m", path); + if (ret == 0) + FAIL_EXIT1 ("zero-length write to \"%s\"", path); + p += ret; + } + xclose (fd); +} diff --git a/support/temp_file-internal.h b/support/temp_file-internal.h new file mode 100644 index 0000000000..fb6cceb065 --- /dev/null +++ b/support/temp_file-internal.h @@ -0,0 +1,31 @@ +/* Internal weak declarations for temporary file handling. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef SUPPORT_TEMP_FILE_INTERNAL_H +#define SUPPORT_TEMP_FILE_INTERNAL_H + +/* These functions are called by the test driver if they are + defined. Tests should not call them directly. */ + +#include + +void support_set_test_dir (const char *name) __attribute__ ((weak)); +void support_delete_temp_files (void) __attribute__ ((weak)); +void support_print_temp_files (FILE *) __attribute__ ((weak)); + +#endif /* SUPPORT_TEMP_FILE_INTERNAL_H */ diff --git a/support/temp_file.c b/support/temp_file.c new file mode 100644 index 0000000000..fdb2477ab9 --- /dev/null +++ b/support/temp_file.c @@ -0,0 +1,132 @@ +/* Temporary file handling for tests. + Copyright (C) 1998-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +/* This is required to get an mkstemp which can create large files on + some 32-bit platforms. */ +#define _FILE_OFFSET_BITS 64 + +#include +#include +#include + +#include +#include +#include +#include +#include + +/* List of temporary files. */ +static struct temp_name_list +{ + struct temp_name_list *next; + char *name; + pid_t owner; +} *temp_name_list; + +/* Location of the temporary files. Set by the test skeleton via + support_set_test_dir. The string is not be freed. */ +static const char *test_dir = _PATH_TMP; + +void +add_temp_file (const char *name) +{ + struct temp_name_list *newp + = (struct temp_name_list *) xcalloc (sizeof (*newp), 1); + char *newname = strdup (name); + if (newname != NULL) + { + newp->name = newname; + newp->next = temp_name_list; + newp->owner = getpid (); + temp_name_list = newp; + } + else + free (newp); +} + +int +create_temp_file (const char *base, char **filename) +{ + char *fname; + int fd; + + fname = (char *) xmalloc (strlen (test_dir) + 1 + strlen (base) + + sizeof ("XXXXXX")); + strcpy (stpcpy (stpcpy (stpcpy (fname, test_dir), "/"), base), "XXXXXX"); + + fd = mkstemp (fname); + if (fd == -1) + { + printf ("cannot open temporary file '%s': %m\n", fname); + free (fname); + return -1; + } + + add_temp_file (fname); + if (filename != NULL) + *filename = fname; + else + free (fname); + + return fd; +} + +/* Helper functions called by the test skeleton follow. */ + +void +support_set_test_dir (const char *path) +{ + test_dir = path; +} + +void +support_delete_temp_files (void) +{ + pid_t pid = getpid (); + while (temp_name_list != NULL) + { + /* Only perform the removal if the path was registed in the same + process, as identified by the PID. (This assumes that the + parent process which registered the temporary file sticks + around, to prevent PID reuse.) */ + if (temp_name_list->owner == pid) + { + if (remove (temp_name_list->name) != 0) + printf ("warning: could not remove temporary file: %s: %m\n", + temp_name_list->name); + } + free (temp_name_list->name); + + struct temp_name_list *next = temp_name_list->next; + free (temp_name_list); + temp_name_list = next; + } +} + +void +support_print_temp_files (FILE *f) +{ + if (temp_name_list != NULL) + { + struct temp_name_list *n; + fprintf (f, "temp_files=(\n"); + for (n = temp_name_list; n != NULL; n = n->next) + fprintf (f, " '%s'\n", n->name); + fprintf (f, ")\n"); + } +} diff --git a/support/temp_file.h b/support/temp_file.h new file mode 100644 index 0000000000..6fed8df1ea --- /dev/null +++ b/support/temp_file.h @@ -0,0 +1,37 @@ +/* Declarations for temporary file handling. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef SUPPORT_TEMP_FILE_H +#define SUPPORT_TEMP_FILE_H + +#include + +__BEGIN_DECLS + +/* Schedule a temporary file for deletion on exit. */ +void add_temp_file (const char *name); + +/* Create a temporary file. Return the opened file descriptor on + success, or -1 on failure. Write the file name to *FILENAME if + FILENAME is not NULL. In this case, the caller is expected to free + *FILENAME. */ +int create_temp_file (const char *base, char **filename); + +__END_DECLS + +#endif /* SUPPORT_TEMP_FILE_H */ diff --git a/support/test-driver.c b/support/test-driver.c new file mode 100644 index 0000000000..482066dbeb --- /dev/null +++ b/support/test-driver.c @@ -0,0 +1,156 @@ +/* Main function for test programs. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +/* This file should be included from test cases. It will define a + main function which provides the test wrapper. + + It assumes that the test case defines a function + + int do_test (void); + + and arranges for that function being called under the test wrapper. + The do_test function should return 0 to indicate a passing test, 1 + to indicate a failing test, or 77 to indicate an unsupported test. + Other result values could be used to indicate a failing test, but + the result of the expression is passed to exit and exit only + returns the lower 8 bits of its input. A non-zero return with some + values could cause a test to incorrectly be considered passing when + it really failed. For this reason, the function should always + return 0 (EXIT_SUCCESS), 1 (EXIT_FAILURE), or 77 + (EXIT_UNSUPPORTED). + + The test function may print out diagnostic or warning messages as well + as messages about failures. These messages should be printed to stdout + and not stderr so that the output is properly ordered with respect to + the rest of the glibc testsuite run output. + + Several preprocessors macros can be defined before including this + file. + + The name of the do_test function can be changed with the + TEST_FUNCTION macro. It must expand to the desired function name. + + If the test case needs access to command line parameters, it must + define the TEST_FUNCTION_ARGV macro with the name of the test + function. It must have the following type: + + int TEST_FUNCTION_ARGV (int argc, char **argv); + + This overrides the do_test default function and is incompatible + with the TEST_FUNCTION macro. + + If PREPARE is defined, it must expand to the name of a function of + the type + + void PREPARE (int argc, char **); + + This function will be called early, after parsing the command line, + but before running the test, in the parent process which acts as + the test supervisor. + + If CLEANUP_HANDLER is defined, it must expand to the name of a + function of the type + + void CLEANUP_HANDLER (void); + + This function will be called from the timeout (SIGALRM) signal + handler. + + If EXPECTED_SIGNAL is defined, it must expanded to a constant which + denotes the expected signal number. + + If EXPECTED_STATUS is defined, it must expand to the expected exit + status. + + If TIMEOUT is defined, it must be positive constant. It overrides + the default test timeout and is measured in seconds. + + If TEST_NO_MALLOPT is defined, the test wrapper will not call + mallopt. + + Custom command line handling can be implemented by defining the + CMDLINE_OPTION macro (after including the header; this + requires _GNU_SOURCE to be defined). This macro must expand to a + to a comma-separated list of braced initializers for struct option + from , with a trailing comma. CMDLINE_PROCESS can be + defined as the name of a function which is called to process these + options. The function is passed the option character/number and + has this type: + + void CMDLINE_PROCESS (int); +*/ + +#include + +#include + +int +main (int argc, char **argv) +{ + struct test_config test_config; + memset (&test_config, 0, sizeof (test_config)); + +#ifdef PREPARE + test_config.prepare_function = (PREPARE); +#endif + +#if defined (TEST_FUNCTION) && defined (TEST_FUNCTON_ARGV) +# error TEST_FUNCTION and TEST_FUNCTION_ARGV cannot be defined at the same time +#endif +#if defined (TEST_FUNCTION) + test_config.test_function = TEST_FUNCTION; +#elif defined (TEST_FUNCTION_ARGV) + test_config.test_function_argv = TEST_FUNCTION_ARGV; +#else + test_config.test_function = do_test; +#endif + +#ifdef CLEANUP_HANDLER + test_config.cleanup_function = CLEANUP_HANDLER; +#endif + +#ifdef EXPECTED_SIGNAL + test_config.expected_signal = (EXPECTED_SIGNAL); +#endif + +#ifdef EXPECTED_STATUS + test_config.expected_status = (EXPECTED_STATUS); +#endif + +#ifdef TEST_NO_MALLOPT + test_config.no_mallopt = 1; +#endif + +#ifdef TIMEOUT + test_config.timeout = TIMEOUT; +#endif + +#ifdef CMDLINE_OPTIONS + struct option options[] = + { + CMDLINE_OPTIONS + TEST_DEFAULT_OPTIONS + }; + test_config.options = &options; +#endif +#ifdef CMDLINE_PROCESS + test_config.cmdline_function = CMDLINE_PROCESS; +#endif + + return support_test_main (argc, argv, &test_config); +} diff --git a/support/test-driver.h b/support/test-driver.h new file mode 100644 index 0000000000..af1971a9ca --- /dev/null +++ b/support/test-driver.h @@ -0,0 +1,74 @@ +/* Interfaces for the test driver. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef SUPPORT_TEST_DRIVER_H +#define SUPPORT_TEST_DRIVER_H + +#include + +__BEGIN_DECLS + +struct test_config +{ + void (*prepare_function) (int argc, char **argv); + int (*test_function) (void); + int (*test_function_argv) (int argc, char **argv); + void (*cleanup_function) (void); + void (*cmdline_function) (int); + const void *options; /* Custom options if not NULL. */ + int timeout; /* Test timeout in seconds. */ + int expected_status; /* Expected exit status. */ + int expected_signal; /* If non-zero, expect termination by signal. */ + char no_mallopt; /* Boolean flag to disable mallopt. */ +}; + +enum + { + /* Test exit status which indicates that the feature is + unsupported. */ + EXIT_UNSUPPORTED = 77, + + /* Default timeout is twenty seconds. Tests should normally + complete faster than this, but if they don't, that's abnormal + (a bug) anyways. */ + DEFAULT_TIMEOUT = 20, + + /* Used for command line argument parsing. */ + OPT_DIRECT = 1000, + OPT_TESTDIR, + }; + +/* Options provided by the test driver. */ +#define TEST_DEFAULT_OPTIONS \ + { "verbose", no_argument, NULL, 'v' }, \ + { "direct", no_argument, NULL, OPT_DIRECT }, \ + { "test-dir", required_argument, NULL, OPT_TESTDIR }, \ + +/* The directory the test should use for temporary files. */ +extern const char *test_dir; + +/* The number of --verbose arguments specified during program + invocation. This variable can be used to control the verbosity of + tests. */ +extern unsigned int test_verbose; + +int support_test_main (int argc, char **argv, const struct test_config *); + +__END_DECLS + +#endif /* SUPPORT_TEST_DRIVER_H */ diff --git a/support/tst-support-namespace.c b/support/tst-support-namespace.c new file mode 100644 index 0000000000..a50b074f5e --- /dev/null +++ b/support/tst-support-namespace.c @@ -0,0 +1,34 @@ +/* Test entering namespaces. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include + +static int +do_test (void) +{ + if (support_become_root ()) + printf ("info: acquired root-like privileges\n"); + if (support_enter_network_namespace ()) + printf ("info: entered network namespace\n"); + if (support_in_uts_namespace ()) + printf ("info: also entered UTS namespace\n"); + return 0; +} + +#include diff --git a/support/tst-support_capture_subprocess.c b/support/tst-support_capture_subprocess.c new file mode 100644 index 0000000000..5672fba0f7 --- /dev/null +++ b/support/tst-support_capture_subprocess.c @@ -0,0 +1,188 @@ +/* Test capturing output from a subprocess. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Write one byte at *P to FD and advance *P. Do nothing if *P is + '\0'. */ +static void +transfer (const unsigned char **p, int fd) +{ + if (**p != '\0') + { + TEST_VERIFY (write (fd, *p, 1) == 1); + ++*p; + } +} + +/* Determine the order in which stdout and stderr are written. */ +enum write_mode { out_first, err_first, interleave, + write_mode_last = interleave }; + +/* Describe what to write in the subprocess. */ +struct test +{ + char *out; + char *err; + enum write_mode write_mode; + int signal; + int status; +}; + +/* For use with support_capture_subprocess. */ +static void +callback (void *closure) +{ + const struct test *test = closure; + bool mode_ok = false; + switch (test->write_mode) + { + case out_first: + TEST_VERIFY (fputs (test->out, stdout) >= 0); + TEST_VERIFY (fflush (stdout) == 0); + TEST_VERIFY (fputs (test->err, stderr) >= 0); + TEST_VERIFY (fflush (stderr) == 0); + mode_ok = true; + break; + case err_first: + TEST_VERIFY (fputs (test->err, stderr) >= 0); + TEST_VERIFY (fflush (stderr) == 0); + TEST_VERIFY (fputs (test->out, stdout) >= 0); + TEST_VERIFY (fflush (stdout) == 0); + mode_ok = true; + break; + case interleave: + { + const unsigned char *pout = (const unsigned char *) test->out; + const unsigned char *perr = (const unsigned char *) test->err; + do + { + transfer (&pout, STDOUT_FILENO); + transfer (&perr, STDERR_FILENO); + } + while (*pout != '\0' || *perr != '\0'); + } + mode_ok = true; + break; + } + TEST_VERIFY (mode_ok); + + if (test->signal != 0) + raise (test->signal); + exit (test->status); +} + +/* Create a heap-allocated random string of letters. */ +static char * +random_string (size_t length) +{ + char *result = xmalloc (length + 1); + for (size_t i = 0; i < length; ++i) + result[i] = 'a' + (rand () % 26); + result[length] = '\0'; + return result; +} + +/* Check that the specific stream from the captured subprocess matches + expectations. */ +static void +check_stream (const char *what, const struct xmemstream *stream, + const char *expected) +{ + if (strcmp (stream->buffer, expected) != 0) + { + support_record_failure (); + printf ("error: captured %s data incorrect\n" + " expected: %s\n" + " actual: %s\n", + what, expected, stream->buffer); + } + if (stream->length != strlen (expected)) + { + support_record_failure (); + printf ("error: captured %s data length incorrect\n" + " expected: %zu\n" + " actual: %zu\n", + what, strlen (expected), stream->length); + } +} + +static int +do_test (void) +{ + const int lengths[] = {0, 1, 17, 512, 20000, -1}; + + /* Test multiple combinations of support_capture_subprocess. + + length_idx_stdout: Index into the lengths array above, + controls how many bytes are written by the subprocess to + standard output. + length_idx_stderr: Same for standard error. + write_mode: How standard output and standard error writes are + ordered. + signal: Exit with no signal if zero, with SIGTERM if one. + status: Process exit status: 0 if zero, 3 if one. */ + for (int length_idx_stdout = 0; lengths[length_idx_stdout] >= 0; + ++length_idx_stdout) + for (int length_idx_stderr = 0; lengths[length_idx_stderr] >= 0; + ++length_idx_stderr) + for (int write_mode = 0; write_mode < write_mode_last; ++write_mode) + for (int signal = 0; signal < 2; ++signal) + for (int status = 0; status < 2; ++status) + { + struct test test = + { + .out = random_string (lengths[length_idx_stdout]), + .err = random_string (lengths[length_idx_stderr]), + .write_mode = write_mode, + .signal = signal * SIGTERM, /* 0 or SIGTERM. */ + .status = status * 3, /* 0 or 3. */ + }; + TEST_VERIFY (strlen (test.out) == lengths[length_idx_stdout]); + TEST_VERIFY (strlen (test.err) == lengths[length_idx_stderr]); + + struct support_capture_subprocess result + = support_capture_subprocess (callback, &test); + check_stream ("stdout", &result.out, test.out); + check_stream ("stderr", &result.err, test.err); + if (test.signal != 0) + { + TEST_VERIFY (WIFSIGNALED (result.status)); + TEST_VERIFY (WTERMSIG (result.status) == test.signal); + } + else + { + TEST_VERIFY (WIFEXITED (result.status)); + TEST_VERIFY (WEXITSTATUS (result.status) == test.status); + } + support_capture_subprocess_free (&result); + free (test.out); + free (test.err); + } + return 0; +} + +#include diff --git a/support/tst-support_format_dns_packet.c b/support/tst-support_format_dns_packet.c new file mode 100644 index 0000000000..9c8589c09c --- /dev/null +++ b/support/tst-support_format_dns_packet.c @@ -0,0 +1,101 @@ +/* Tests for the support_format_dns_packet function. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include + +#include +#include +#include + +static void +check_packet (const void *buffer, size_t length, + const char *name, const char *expected) +{ + char *actual = support_format_dns_packet (buffer, length); + if (strcmp (actual, expected) != 0) + { + support_record_failure (); + printf ("error: formatted packet does not match: %s\n", name); + support_run_diff ("expected", expected, + "actual", actual); + } + free (actual); +} + +static void +test_aaaa_length (void) +{ + static const char packet[] = + /* Header: Response with two records. */ + "\x12\x34\x80\x00\x00\x01\x00\x02\x00\x00\x00\x00" + /* Question section. www.example/IN/AAAA. */ + "\x03www\x07""example\x00\x00\x1c\x00\x01" + /* Answer section. www.example AAAA [corrupted]. */ + "\xc0\x0c" + "\x00\x1c\x00\x01\x00\x00\x00\x00\x00\x10" + "\x20\x01\x0d\xb8\x05\x06\x07\x08" + "\x11\x12\x13\x14\x15\x16\x17\x18" + /* www.example AAAA [corrupted]. */ + "\xc0\x0c" + "\x00\x1c\x00\x01\x00\x00\x00\x00\x00\x11" + "\x01\x02\x03\x04\x05\x06\x07\x08" + "\x11\x12\x13\x14\x15\x16\x17\x18" "\xff"; + check_packet (packet, sizeof (packet) - 1, __func__, + "name: www.example\n" + "address: 2001:db8:506:708:1112:1314:1516:1718\n" + "error: AAAA record of size 17: www.example\n"); +} + +static void +test_multiple_cnames (void) +{ + static const char packet[] = + /* Header: Response with three records. */ + "\x12\x34\x80\x00\x00\x01\x00\x03\x00\x00\x00\x00" + /* Question section. www.example/IN/A. */ + "\x03www\x07""example\x00\x00\x01\x00\x01" + /* Answer section. www.example CNAME www1.example. */ + "\xc0\x0c" + "\x00\x05\x00\x01\x00\x00\x00\x00\x00\x07" + "\x04www1\xc0\x10" + /* www1 CNAME www2. */ + "\x04www1\xc0\x10" + "\x00\x05\x00\x01\x00\x00\x00\x00\x00\x07" + "\x04www2\xc0\x10" + /* www2 A 192.0.2.1. */ + "\x04www2\xc0\x10" + "\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04" + "\xc0\x00\x02\x01"; + check_packet (packet, sizeof (packet) - 1, __func__, + "name: www.example\n" + "name: www1.example\n" + "name: www2.example\n" + "address: 192.0.2.1\n"); +} + +static int +do_test (void) +{ + test_aaaa_length (); + test_multiple_cnames (); + return 0; +} + +#include diff --git a/support/tst-support_record_failure-2.sh b/support/tst-support_record_failure-2.sh new file mode 100644 index 0000000000..2c9372cc29 --- /dev/null +++ b/support/tst-support_record_failure-2.sh @@ -0,0 +1,69 @@ +#!/bin/sh +# Test failure recording (with and without --direct). +# Copyright (C) 2016-2017 Free Software Foundation, Inc. +# This file is part of the GNU C Library. + +# The GNU C Library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# The GNU C Library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with the GNU C Library; if not, see +# . */ + +set -e + +common_objpfx=$1; shift +test_program_prefix_before_env=$1; shift +run_program_env=$1; shift +test_program_prefix_after_env=$1; shift + +run_test () { + expected_status="$1" + expected_output="$2" + shift 2 + args="${common_objpfx}support/tst-support_record_failure $*" + echo "running: $args" + set +e + output="$(${test_program_prefix_before_env} \ + ${run_program} ${test_program_prefix_after_env} $args)" + status=$? + set -e + echo " exit status: $status" + if test "$output" != "$expected_output" ; then + echo "error: unexpected output: $output" + exit 1 + fi + if test "$status" -ne "$expected_status" ; then + echo "error: exit status $expected_status expected" + exit 1 + fi +} + +different_status () { + direct="$1" + run_test 1 "error: 1 test failures" $direct --status=0 + run_test 1 "error: 1 test failures" $direct --status=1 + run_test 2 "error: 1 test failures" $direct --status=2 + run_test 1 "error: 1 test failures" $direct --status=77 + run_test 2 "error: tst-support_record_failure.c:109: not true: false +error: 1 test failures" $direct --test-verify + run_test 2 "error: tst-support_record_failure.c:109: not true: false +info: execution passed failed TEST_VERIFY +error: 1 test failures" $direct --test-verify --verbose +} + +different_status +different_status --direct + +run_test 1 "error: tst-support_record_failure.c:116: not true: false +error: 1 test failures" --test-verify-exit +# --direct does not print the summary error message if exit is called. +run_test 1 "error: tst-support_record_failure.c:116: not true: false" \ + --direct --test-verify-exit diff --git a/support/tst-support_record_failure.c b/support/tst-support_record_failure.c new file mode 100644 index 0000000000..e739e739c3 --- /dev/null +++ b/support/tst-support_record_failure.c @@ -0,0 +1,153 @@ +/* Test support_record_failure state sharing. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +static int exit_status_with_failure = -1; +static bool test_verify; +static bool test_verify_exit; +enum + { + OPT_STATUS = 10001, + OPT_TEST_VERIFY, + OPT_TEST_VERIFY_EXIT, + }; +#define CMDLINE_OPTIONS \ + { "status", required_argument, NULL, OPT_STATUS }, \ + { "test-verify", no_argument, NULL, OPT_TEST_VERIFY }, \ + { "test-verify-exit", no_argument, NULL, OPT_TEST_VERIFY_EXIT }, +static void +cmdline_process (int c) +{ + switch (c) + { + case OPT_STATUS: + exit_status_with_failure = atoi (optarg); + break; + case OPT_TEST_VERIFY: + test_verify = true; + break; + case OPT_TEST_VERIFY_EXIT: + test_verify_exit = true; + break; + } +} +#define CMDLINE_PROCESS cmdline_process + +static void +check_failure_reporting (int phase, int zero, int unsupported) +{ + int status = support_report_failure (0); + if (status != zero) + { + printf ("real-error (phase %d): support_report_failure (0) == %d\n", + phase, status); + exit (1); + } + status = support_report_failure (1); + if (status != 1) + { + printf ("real-error (phase %d): support_report_failure (1) == %d\n", + phase, status); + exit (1); + } + status = support_report_failure (2); + if (status != 2) + { + printf ("real-error (phase %d): support_report_failure (2) == %d\n", + phase, status); + exit (1); + } + status = support_report_failure (EXIT_UNSUPPORTED); + if (status != unsupported) + { + printf ("real-error (phase %d): " + "support_report_failure (EXIT_UNSUPPORTED) == %d\n", + phase, status); + exit (1); + } +} + +static int +do_test (void) +{ + if (exit_status_with_failure >= 0) + { + /* External invocation with requested error status. Used by + tst-support_report_failure-2.sh. */ + support_record_failure (); + return exit_status_with_failure; + } + TEST_VERIFY (true); + TEST_VERIFY_EXIT (true); + if (test_verify) + { + TEST_VERIFY (false); + if (test_verbose) + printf ("info: execution passed failed TEST_VERIFY\n"); + return 2; /* Expected exit status. */ + } + if (test_verify_exit) + { + TEST_VERIFY_EXIT (false); + return 3; /* Not reached. Expected exit status is 1. */ + } + + printf ("info: This test tests the test framework.\n" + "info: It reports some expected errors on stdout.\n"); + + /* Check that the status is passed through unchanged. */ + check_failure_reporting (1, 0, EXIT_UNSUPPORTED); + + /* Check state propagation from a subprocess. */ + pid_t pid = xfork (); + if (pid == 0) + { + support_record_failure (); + _exit (0); + } + int status; + xwaitpid (pid, &status, 0); + if (status != 0) + { + printf ("real-error: incorrect status from subprocess: %d\n", status); + return 1; + } + check_failure_reporting (2, 1, 1); + + /* Also test directly in the parent process. */ + support_record_failure_reset (); + check_failure_reporting (3, 0, EXIT_UNSUPPORTED); + support_record_failure (); + check_failure_reporting (4, 1, 1); + + /* We need to mask the failure above. */ + support_record_failure_reset (); + return 0; +} + +#include diff --git a/sysdeps/unix/sysv/linux/sh/pwrite64.c b/support/write_message.c similarity index 68% rename from sysdeps/unix/sysv/linux/sh/pwrite64.c rename to support/write_message.c index 683a5d9886..f03ed931d6 100644 --- a/sysdeps/unix/sysv/linux/sh/pwrite64.c +++ b/support/write_message.c @@ -1,6 +1,6 @@ -/* Copyright (C) 1997-2016 Free Software Foundation, Inc. +/* Write a message to standard output. + Copyright (C) 2016-2017 Free Software Foundation, Inc. This file is part of the GNU C Library. - Contributed by Ralf Baechle , 1998. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -16,8 +16,14 @@ License along with the GNU C Library; if not, see . */ -/* SH4 ABI does not really require argument alignment for 64-bits, but - the kernel interface for pread adds a dummy long argument before the - offset. */ -#define __ALIGNMENT_ARG -#include +#include + +#include +#include + +void +write_message (const char *message) +{ + ssize_t unused __attribute__ ((unused)); + unused = write (STDOUT_FILENO, message, strlen (message)); +} diff --git a/support/xaccept.c b/support/xaccept.c new file mode 100644 index 0000000000..7b25af3b05 --- /dev/null +++ b/support/xaccept.c @@ -0,0 +1,32 @@ +/* accept with error checking. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include + +int +xaccept (int fd, struct sockaddr *sa, socklen_t *salen) +{ + int clientfd = accept (fd, sa, salen); + if (clientfd < 0) + FAIL_EXIT1 ("accept (%d): %m", fd); + return clientfd; +} diff --git a/support/xaccept4.c b/support/xaccept4.c new file mode 100644 index 0000000000..67dd95e9fb --- /dev/null +++ b/support/xaccept4.c @@ -0,0 +1,32 @@ +/* accept4 with error checking. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include + +int +xaccept4 (int fd, struct sockaddr *sa, socklen_t *salen, int flags) +{ + int clientfd = accept4 (fd, sa, salen, flags); + if (clientfd < 0) + FAIL_EXIT1 ("accept4 (%d, 0x%x): %m", fd, flags); + return clientfd; +} diff --git a/support/xasprintf.c b/support/xasprintf.c new file mode 100644 index 0000000000..5157680fa2 --- /dev/null +++ b/support/xasprintf.c @@ -0,0 +1,36 @@ +/* Error-checking wrapper for asprintf. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include +#include + +char * +xasprintf (const char *format, ...) +{ + va_list ap; + va_start (ap, format); + char *result; + if (vasprintf (&result, format, ap) < 0) + FAIL_EXIT1 ("asprintf: %m"); + va_end (ap); + return result; +} diff --git a/support/xbind.c b/support/xbind.c new file mode 100644 index 0000000000..cfc6dd8fa8 --- /dev/null +++ b/support/xbind.c @@ -0,0 +1,30 @@ +/* bind with error checking. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include + +void +xbind (int fd, const struct sockaddr *sa, socklen_t sa_len) +{ + if (bind (fd, sa, sa_len) != 0) + FAIL_EXIT1 ("bind (%d), family %d: %m", fd, sa->sa_family); +} diff --git a/sysdeps/unix/sysv/linux/sh/pread64.c b/support/xcalloc.c similarity index 67% rename from sysdeps/unix/sysv/linux/sh/pread64.c rename to support/xcalloc.c index b2e8a25788..135f42dab2 100644 --- a/sysdeps/unix/sysv/linux/sh/pread64.c +++ b/support/xcalloc.c @@ -1,6 +1,6 @@ -/* Copyright (C) 1997-2016 Free Software Foundation, Inc. +/* Error-checking wrapper for calloc. + Copyright (C) 2016-2017 Free Software Foundation, Inc. This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1997. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -16,8 +16,19 @@ License along with the GNU C Library; if not, see . */ -/* SH4 ABI does not really require argument alignment for 64-bits, but - the kernel interface for pread adds a dummy long argument before the - offset. */ -#define __ALIGNMENT_ARG -#include +#include + +#include +#include +#include + +void * +xcalloc (size_t n, size_t s) +{ + void *p; + + p = calloc (n, s); + if (p == NULL) + oom_error ("calloc", n * s); + return p; +} diff --git a/support/xchroot.c b/support/xchroot.c new file mode 100644 index 0000000000..abcc299e00 --- /dev/null +++ b/support/xchroot.c @@ -0,0 +1,28 @@ +/* chroot with error checking. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include + +void +xchroot (const char *path) +{ + if (chroot (path) != 0) + FAIL_EXIT1 ("chroot (\"%s\"): %m", path); +} diff --git a/support/xclose.c b/support/xclose.c new file mode 100644 index 0000000000..c931e08421 --- /dev/null +++ b/support/xclose.c @@ -0,0 +1,28 @@ +/* close with error checking. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include + +void +xclose (int fd) +{ + if (close (fd) < 0 && errno != EINTR) + FAIL_EXIT1 ("close of descriptor %d failed: %m", fd); +} diff --git a/support/xconnect.c b/support/xconnect.c new file mode 100644 index 0000000000..0266dbc643 --- /dev/null +++ b/support/xconnect.c @@ -0,0 +1,30 @@ +/* connect with error checking. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include + +void +xconnect (int fd, const struct sockaddr *sa, socklen_t sa_len) +{ + if (connect (fd, sa, sa_len) != 0) + FAIL_EXIT1 ("connect (%d), family %d: %m", fd, sa->sa_family); +} diff --git a/support/xdup2.c b/support/xdup2.c new file mode 100644 index 0000000000..dc08c94518 --- /dev/null +++ b/support/xdup2.c @@ -0,0 +1,28 @@ +/* dup2 with error checking. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include + +void +xdup2 (int from, int to) +{ + if (dup2 (from, to) < 0) + FAIL_EXIT1 ("dup2 (%d, %d): %m", from, to); +} diff --git a/support/xfclose.c b/support/xfclose.c new file mode 100644 index 0000000000..2737f05044 --- /dev/null +++ b/support/xfclose.c @@ -0,0 +1,33 @@ +/* fclose with error checking. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include + +void +xfclose (FILE *fp) +{ + if (ferror (fp)) + FAIL_EXIT1 ("stdio stream closed with pending errors"); + if (fflush (fp) != 0) + FAIL_EXIT1 ("fflush: %m"); + if (fclose (fp) != 0) + FAIL_EXIT1 ("fclose: %m"); +} diff --git a/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdimf-vis3.S b/support/xfopen.c similarity index 67% rename from sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdimf-vis3.S rename to support/xfopen.c index 081fc15b62..14532a09f3 100644 --- a/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdimf-vis3.S +++ b/support/xfopen.c @@ -1,7 +1,6 @@ -/* Compute positive difference, sparc 32-bit+v9+vis3. - Copyright (C) 2013-2016 Free Software Foundation, Inc. +/* fopen with error checking. + Copyright (C) 2016-2017 Free Software Foundation, Inc. This file is part of the GNU C Library. - Contributed by David S. Miller . The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -17,16 +16,16 @@ License along with the GNU C Library; if not, see . */ -#include +#include -ENTRY(__fdimf_vis3) - movwtos %o0, %f0 - movwtos %o1, %f1 - fcmps %f0, %f1 - fbug 1f - nop - fzeros %f0 - fnegs %f0, %f1 -1: retl - fsubs %f0, %f1, %f0 -END(__fdimf_vis3) +#include +#include + +FILE * +xfopen (const char *path, const char *mode) +{ + FILE *fp = fopen (path, mode); + if (fp == NULL) + FAIL_EXIT1 ("could not open %s (mode \"%s\"): %m", path, mode); + return fp; +} diff --git a/support/xfork.c b/support/xfork.c new file mode 100644 index 0000000000..aa52ba62c5 --- /dev/null +++ b/support/xfork.c @@ -0,0 +1,32 @@ +/* fork with error checking. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include + +pid_t +xfork (void) +{ + pid_t result = fork (); + if (result < 0) + FAIL_EXIT1 ("fork: %m"); + return result; +} diff --git a/support/xgetsockname.c b/support/xgetsockname.c new file mode 100644 index 0000000000..c3bd884f8d --- /dev/null +++ b/support/xgetsockname.c @@ -0,0 +1,30 @@ +/* getsockname with error checking. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include + +void +xgetsockname (int fd, struct sockaddr *sa, socklen_t *plen) +{ + if (getsockname (fd, sa, plen) != 0) + FAIL_EXIT1 ("setsockopt (%d): %m", fd); +} diff --git a/support/xlisten.c b/support/xlisten.c new file mode 100644 index 0000000000..1953e5900a --- /dev/null +++ b/support/xlisten.c @@ -0,0 +1,30 @@ +/* listen with error checking. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include + +void +xlisten (int fd, int backlog) +{ + if (listen (fd, backlog) != 0) + FAIL_EXIT1 ("listen (%d, %d): %m", fd, backlog); +} diff --git a/support/xmalloc.c b/support/xmalloc.c new file mode 100644 index 0000000000..450f699789 --- /dev/null +++ b/support/xmalloc.c @@ -0,0 +1,34 @@ +/* Error-checking wrapper for malloc. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include + +void * +xmalloc (size_t n) +{ + void *p; + + p = malloc (n); + if (p == NULL) + oom_error ("malloc", n); + return p; +} diff --git a/sysdeps/sparc/sparc32/fpu/s_fdim.S b/support/xmemstream.c similarity index 54% rename from sysdeps/sparc/sparc32/fpu/s_fdim.S rename to support/xmemstream.c index e93970faae..bce6dc9170 100644 --- a/sysdeps/sparc/sparc32/fpu/s_fdim.S +++ b/support/xmemstream.c @@ -1,7 +1,6 @@ -/* Compute positive difference, sparc 32-bit. - Copyright (C) 2013-2016 Free Software Foundation, Inc. +/* Error-checking wrappers for memstream functions. + Copyright (C) 2016-2017 Free Software Foundation, Inc. This file is part of the GNU C Library. - Contributed by David S. Miller . The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -17,26 +16,27 @@ License along with the GNU C Library; if not, see . */ -#include -#include +#include -ENTRY(__fdim) - std %o0, [%sp + 72] - std %o2, [%sp + 80] - ldd [%sp + 72], %f0 - ldd [%sp + 80], %f2 - fcmpd %f0, %f2 - st %g0, [%sp + 72] - fbug 1f - st %g0, [%sp + 76] - ldd [%sp + 72], %f0 - fnegs %f0, %f2 - fmovs %f1, %f3 -1: retl - fsubd %f0, %f2, %f0 -END(__fdim) -weak_alias (__fdim, fdim) +#include +#include +#include +#include -#if LONG_DOUBLE_COMPAT(libm, GLIBC_2_1) -compat_symbol (libm, __fdim, fdiml, GLIBC_2_1); -#endif +void +xopen_memstream (struct xmemstream *stream) +{ + int old_errno = errno; + *stream = (struct xmemstream) {}; + stream->out = open_memstream (&stream->buffer, &stream->length); + if (stream->out == NULL) + FAIL_EXIT1 ("open_memstream: %m"); + errno = old_errno; +} + +void +xfclose_memstream (struct xmemstream *stream) +{ + xfclose (stream->out); + stream->out = NULL; +} diff --git a/support/xmemstream.h b/support/xmemstream.h new file mode 100644 index 0000000000..e5ba231e4d --- /dev/null +++ b/support/xmemstream.h @@ -0,0 +1,49 @@ +/* Error-checking wrappers for memstream functions. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef SUPPORT_XMEMSTREAM_H +#define SUPPORT_XMEMSTREAM_H + +#include +#include + +__BEGIN_DECLS + +/* Wrappers for other libc functions. */ +struct xmemstream +{ + FILE *out; + char *buffer; + size_t length; +}; + +/* Create a new in-memory stream. Initializes *STREAM. After this + function returns, STREAM->out is a file descriptor open for + writing. errno is preserved, so that the %m format specifier can + be used for writing to STREAM->out. */ +void xopen_memstream (struct xmemstream *stream); + +/* Closes STREAM->OUT. After this function returns, STREAM->buffer + and STREAM->length denote a memory range which contains the bytes + written to the output stream. The caller should free + STREAM->buffer. */ +void xfclose_memstream (struct xmemstream *stream); + +__END_DECLS + +#endif /* SUPPORT_XMEMSTREAM_H */ diff --git a/support/xmkdir.c b/support/xmkdir.c new file mode 100644 index 0000000000..ea17d49391 --- /dev/null +++ b/support/xmkdir.c @@ -0,0 +1,28 @@ +/* mkdir with error checking. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include + +void +xmkdir (const char *path, mode_t mode) +{ + if (mkdir (path, mode) != 0) + FAIL_EXIT1 ("mkdir (\"%s\", 0%o): %m", path, mode); +} diff --git a/support/xmmap.c b/support/xmmap.c new file mode 100644 index 0000000000..435b1eb733 --- /dev/null +++ b/support/xmmap.c @@ -0,0 +1,31 @@ +/* mmap with error checking. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include + +void * +xmmap (void *addr, size_t length, int prot, int flags, int fd) +{ + void *result = mmap (addr, length, prot, flags, fd, 0); + if (result == MAP_FAILED) + FAIL_EXIT1 ("mmap of %zu bytes, prot=0x%x, flags=0x%x: %m", + length, prot, flags); + return result; +} diff --git a/support/xmunmap.c b/support/xmunmap.c new file mode 100644 index 0000000000..6ef5a4a468 --- /dev/null +++ b/support/xmunmap.c @@ -0,0 +1,28 @@ +/* munmap with error checking. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include + +void +xmunmap (void *addr, size_t length) +{ + if (munmap (addr, length) != 0) + FAIL_EXIT1 ("munmap of %zu bytes: %m", length); +} diff --git a/support/xopen.c b/support/xopen.c new file mode 100644 index 0000000000..7f033a03a7 --- /dev/null +++ b/support/xopen.c @@ -0,0 +1,30 @@ +/* open64 with error checking. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include + +int +xopen (const char *path, int flags, mode_t mode) +{ + int ret = open64 (path, flags, mode); + if (ret < 0) + FAIL_EXIT1 ("open64 (\"%s\", 0x%x, 0%o): %m", path, flags, mode); + return ret; +} diff --git a/support/xpipe.c b/support/xpipe.c new file mode 100644 index 0000000000..89a64a55c1 --- /dev/null +++ b/support/xpipe.c @@ -0,0 +1,28 @@ +/* pipe with error checking. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include + +void +xpipe (int fds[2]) +{ + if (pipe (fds) < 0) + FAIL_EXIT1 ("pipe: %m"); +} diff --git a/support/xpoll.c b/support/xpoll.c new file mode 100644 index 0000000000..bec2521ffc --- /dev/null +++ b/support/xpoll.c @@ -0,0 +1,32 @@ +/* poll with error checking. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include + +int +xpoll (struct pollfd *fds, nfds_t nfds, int timeout) +{ + int ret = poll (fds, nfds, timeout); + if (ret < 0) + FAIL_EXIT1 ("poll: %m"); + return ret; +} diff --git a/support/xpthread_attr_destroy.c b/support/xpthread_attr_destroy.c new file mode 100644 index 0000000000..664c809e9f --- /dev/null +++ b/support/xpthread_attr_destroy.c @@ -0,0 +1,26 @@ +/* pthread_attr_destroy with error checking. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +void +xpthread_attr_destroy (pthread_attr_t *attr) +{ + xpthread_check_return ("pthread_attr_destroy", + pthread_attr_destroy (attr)); +} diff --git a/support/xpthread_attr_init.c b/support/xpthread_attr_init.c new file mode 100644 index 0000000000..2e30ade9ab --- /dev/null +++ b/support/xpthread_attr_init.c @@ -0,0 +1,25 @@ +/* pthread_attr_init with error checking. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +void +xpthread_attr_init (pthread_attr_t *attr) +{ + xpthread_check_return ("pthread_attr_init", pthread_attr_init (attr)); +} diff --git a/support/xpthread_attr_setdetachstate.c b/support/xpthread_attr_setdetachstate.c new file mode 100644 index 0000000000..b544dbaa42 --- /dev/null +++ b/support/xpthread_attr_setdetachstate.c @@ -0,0 +1,27 @@ +/* pthread_attr_setdetachstate with error checking. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +void +xpthread_attr_setdetachstate (pthread_attr_t *attr, int detachstate) +{ + xpthread_check_return ("pthread_attr_setdetachstate", + pthread_attr_setdetachstate (attr, + detachstate)); +} diff --git a/support/xpthread_attr_setstacksize.c b/support/xpthread_attr_setstacksize.c new file mode 100644 index 0000000000..02d06310a9 --- /dev/null +++ b/support/xpthread_attr_setstacksize.c @@ -0,0 +1,26 @@ +/* pthread_attr_setstacksize with error checking. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +void +xpthread_attr_setstacksize (pthread_attr_t *attr, size_t stacksize) +{ + xpthread_check_return ("pthread_attr_setstacksize", + pthread_attr_setstacksize (attr, stacksize)); +} diff --git a/support/xpthread_barrier_destroy.c b/support/xpthread_barrier_destroy.c new file mode 100644 index 0000000000..efc0719a63 --- /dev/null +++ b/support/xpthread_barrier_destroy.c @@ -0,0 +1,26 @@ +/* pthread_barrier_destroy with error checking. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +void +xpthread_barrier_destroy (pthread_barrier_t *barrier) +{ + xpthread_check_return ("pthread_barrier_destroy", + pthread_barrier_destroy (barrier)); +} diff --git a/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdim-vis3.S b/support/xpthread_barrier_init.c similarity index 65% rename from sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdim-vis3.S rename to support/xpthread_barrier_init.c index 4a479b1a59..b32dad1315 100644 --- a/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdim-vis3.S +++ b/support/xpthread_barrier_init.c @@ -1,7 +1,6 @@ -/* Compute positive difference, sparc 32-bit+v9+vis3. - Copyright (C) 2013-2016 Free Software Foundation, Inc. +/* pthread_barrier_init with error checking. + Copyright (C) 2016-2017 Free Software Foundation, Inc. This file is part of the GNU C Library. - Contributed by David S. Miller . The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -17,18 +16,12 @@ License along with the GNU C Library; if not, see . */ -#include +#include -ENTRY(__fdim_vis3) - movwtos %o0, %f0 - movwtos %o1, %f1 - movwtos %o2, %f2 - movwtos %o3, %f3 - fcmpd %f0, %f2 - fbug 1f - nop - fzero %f0 - fnegd %f0, %f2 -1: retl - fsubd %f0, %f2, %f0 -END(__fdim_vis3) +void +xpthread_barrier_init (pthread_barrier_t *barrier, + pthread_barrierattr_t *attr, unsigned int count) +{ + xpthread_check_return ("pthread_barrier_init", + pthread_barrier_init (barrier, attr, count)); +} diff --git a/support/xpthread_barrier_wait.c b/support/xpthread_barrier_wait.c new file mode 100644 index 0000000000..7cee44d0a3 --- /dev/null +++ b/support/xpthread_barrier_wait.c @@ -0,0 +1,28 @@ +/* pthread_barrier_wait with error checking. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +int +xpthread_barrier_wait (pthread_barrier_t *barrier) +{ + int ret = pthread_barrier_wait (barrier); + if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD) + xpthread_check_return ("pthread_barrier_wait", ret); + return ret == PTHREAD_BARRIER_SERIAL_THREAD; +} diff --git a/support/xpthread_cancel.c b/support/xpthread_cancel.c new file mode 100644 index 0000000000..3af16f9b54 --- /dev/null +++ b/support/xpthread_cancel.c @@ -0,0 +1,25 @@ +/* pthread_cancel with error checking. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +void +xpthread_cancel (pthread_t thr) +{ + xpthread_check_return ("pthread_cancel", pthread_cancel (thr)); +} diff --git a/support/xpthread_check_return.c b/support/xpthread_check_return.c new file mode 100644 index 0000000000..3094d82e9c --- /dev/null +++ b/support/xpthread_check_return.c @@ -0,0 +1,34 @@ +/* Return value checking for pthread functions, exit variant. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include +#include + +void +xpthread_check_return (const char *function, int value) +{ + if (value != 0) + { + errno = value; + FAIL_EXIT1 ("%s: %m", function); + } +} diff --git a/support/xpthread_cond_wait.c b/support/xpthread_cond_wait.c new file mode 100644 index 0000000000..b0e9b2a232 --- /dev/null +++ b/support/xpthread_cond_wait.c @@ -0,0 +1,26 @@ +/* pthread_cond_wait with error checking. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +void +xpthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex) +{ + xpthread_check_return + ("pthread_cond_wait", pthread_cond_wait (cond, mutex)); +} diff --git a/support/xpthread_create.c b/support/xpthread_create.c new file mode 100644 index 0000000000..98c63e54c3 --- /dev/null +++ b/support/xpthread_create.c @@ -0,0 +1,29 @@ +/* pthread_create with error checking. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +pthread_t +xpthread_create (pthread_attr_t *attr, + void *(*thread_func) (void *), void *closure) +{ + pthread_t thr; + xpthread_check_return + ("pthread_create", pthread_create (&thr, attr, thread_func, closure)); + return thr; +} diff --git a/support/xpthread_detach.c b/support/xpthread_detach.c new file mode 100644 index 0000000000..2088af2f57 --- /dev/null +++ b/support/xpthread_detach.c @@ -0,0 +1,25 @@ +/* pthread_detach with error checking. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +void +xpthread_detach (pthread_t thr) +{ + xpthread_check_return ("pthread_detach", pthread_detach (thr)); +} diff --git a/support/xpthread_join.c b/support/xpthread_join.c new file mode 100644 index 0000000000..f23bb9a5ae --- /dev/null +++ b/support/xpthread_join.c @@ -0,0 +1,27 @@ +/* pthread_join with error checking. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +void * +xpthread_join (pthread_t thr) +{ + void *result; + xpthread_check_return ("pthread_join", pthread_join (thr, &result)); + return result; +} diff --git a/support/xpthread_mutex_consistent.c b/support/xpthread_mutex_consistent.c new file mode 100644 index 0000000000..52364be365 --- /dev/null +++ b/support/xpthread_mutex_consistent.c @@ -0,0 +1,26 @@ +/* pthread_mutex_consistent with error checking. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +void +xpthread_mutex_consistent (pthread_mutex_t *mutex) +{ + xpthread_check_return ("pthread_mutex_consistent", + pthread_mutex_consistent (mutex)); +} diff --git a/support/xpthread_mutex_destroy.c b/support/xpthread_mutex_destroy.c new file mode 100644 index 0000000000..f11f8f0acd --- /dev/null +++ b/support/xpthread_mutex_destroy.c @@ -0,0 +1,26 @@ +/* pthread_mutex_destroy with error checking. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +void +xpthread_mutex_destroy (pthread_mutex_t *mutex) +{ + xpthread_check_return ("pthread_mutex_destroy", + pthread_mutex_destroy (mutex)); +} diff --git a/support/xpthread_mutex_init.c b/support/xpthread_mutex_init.c new file mode 100644 index 0000000000..2d16d1b9d9 --- /dev/null +++ b/support/xpthread_mutex_init.c @@ -0,0 +1,26 @@ +/* pthread_mutex_init with error checking. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +void +xpthread_mutex_init (pthread_mutex_t *mutex, const pthread_mutexattr_t *attr) +{ + xpthread_check_return ("pthread_mutex_init", + pthread_mutex_init (mutex, attr)); +} diff --git a/support/xpthread_mutex_lock.c b/support/xpthread_mutex_lock.c new file mode 100644 index 0000000000..af727b45f3 --- /dev/null +++ b/support/xpthread_mutex_lock.c @@ -0,0 +1,25 @@ +/* pthread_mutex_lock with error checking. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +void +xpthread_mutex_lock (pthread_mutex_t *mutex) +{ + xpthread_check_return ("pthread_mutex_lock", pthread_mutex_lock (mutex)); +} diff --git a/support/xpthread_mutex_unlock.c b/support/xpthread_mutex_unlock.c new file mode 100644 index 0000000000..161b41edf6 --- /dev/null +++ b/support/xpthread_mutex_unlock.c @@ -0,0 +1,25 @@ +/* pthread_mutex_unlock with error checking. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +void +xpthread_mutex_unlock (pthread_mutex_t *mutex) +{ + xpthread_check_return ("pthread_mutex_unlock", pthread_mutex_unlock (mutex)); +} diff --git a/support/xpthread_mutexattr_destroy.c b/support/xpthread_mutexattr_destroy.c new file mode 100644 index 0000000000..c699e32b41 --- /dev/null +++ b/support/xpthread_mutexattr_destroy.c @@ -0,0 +1,26 @@ +/* pthread_mutexattr_destroy with error checking. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +void +xpthread_mutexattr_destroy (pthread_mutexattr_t *attr) +{ + xpthread_check_return ("pthread_mutexattr_destroy", + pthread_mutexattr_destroy (attr)); +} diff --git a/support/xpthread_mutexattr_init.c b/support/xpthread_mutexattr_init.c new file mode 100644 index 0000000000..fa93fab178 --- /dev/null +++ b/support/xpthread_mutexattr_init.c @@ -0,0 +1,25 @@ +/* pthread_mutexattr_init with error checking. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +void +xpthread_mutexattr_init (pthread_mutexattr_t *attr) +{ + xpthread_check_return ("pthread_mutexattr_init", pthread_mutexattr_init (attr)); +} diff --git a/sysdeps/sparc/sparc64/fpu/s_fdim.S b/support/xpthread_mutexattr_setprotocol.c similarity index 67% rename from sysdeps/sparc/sparc64/fpu/s_fdim.S rename to support/xpthread_mutexattr_setprotocol.c index 7fae72a251..353f75e3d7 100644 --- a/sysdeps/sparc/sparc64/fpu/s_fdim.S +++ b/support/xpthread_mutexattr_setprotocol.c @@ -1,7 +1,6 @@ -/* Compute positive difference, sparc 64-bit. - Copyright (C) 2013-2016 Free Software Foundation, Inc. +/* pthread_mutexattr_setprotocol with error checking. + Copyright (C) 2016-2017 Free Software Foundation, Inc. This file is part of the GNU C Library. - Contributed by David S. Miller . The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -17,16 +16,11 @@ License along with the GNU C Library; if not, see . */ -#include -#include +#include -ENTRY(__fdim) - fcmpd %f0, %f2 - fbug 1f - nop - fzero %f0 - fnegd %f0, %f2 -1: retl - fsubd %f0, %f2, %f0 -END(__fdim) -weak_alias (__fdim, fdim) +void +xpthread_mutexattr_setprotocol (pthread_mutexattr_t *attr, int flag) +{ + xpthread_check_return ("pthread_mutexattr_setprotocol", + pthread_mutexattr_setprotocol (attr, flag)); +} diff --git a/support/xpthread_mutexattr_setpshared.c b/support/xpthread_mutexattr_setpshared.c new file mode 100644 index 0000000000..242da1aeca --- /dev/null +++ b/support/xpthread_mutexattr_setpshared.c @@ -0,0 +1,26 @@ +/* pthread_mutexattr_setpshared with error checking. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +void +xpthread_mutexattr_setpshared (pthread_mutexattr_t *attr, int flag) +{ + xpthread_check_return ("pthread_mutexattr_setpshared", + pthread_mutexattr_setpshared (attr, flag)); +} diff --git a/support/xpthread_mutexattr_setrobust.c b/support/xpthread_mutexattr_setrobust.c new file mode 100644 index 0000000000..d7d6fa8630 --- /dev/null +++ b/support/xpthread_mutexattr_setrobust.c @@ -0,0 +1,26 @@ +/* pthread_mutexattr_setrobust with error checking. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +void +xpthread_mutexattr_setrobust (pthread_mutexattr_t *attr, int flag) +{ + xpthread_check_return ("pthread_mutexattr_setrobust", + pthread_mutexattr_setrobust (attr, flag)); +} diff --git a/support/xpthread_mutexattr_settype.c b/support/xpthread_mutexattr_settype.c new file mode 100644 index 0000000000..cf22170b56 --- /dev/null +++ b/support/xpthread_mutexattr_settype.c @@ -0,0 +1,26 @@ +/* pthread_mutexattr_settype with error checking. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +void +xpthread_mutexattr_settype (pthread_mutexattr_t *attr, int flag) +{ + xpthread_check_return ("pthread_mutexattr_settype", + pthread_mutexattr_settype (attr, flag)); +} diff --git a/support/xpthread_once.c b/support/xpthread_once.c new file mode 100644 index 0000000000..70d58dbab2 --- /dev/null +++ b/support/xpthread_once.c @@ -0,0 +1,25 @@ +/* pthread_once with error checking. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +void +xpthread_once (pthread_once_t *guard, void (*func) (void)) +{ + xpthread_check_return ("pthread_once", pthread_once (guard, func)); +} diff --git a/support/xpthread_sigmask.c b/support/xpthread_sigmask.c new file mode 100644 index 0000000000..0ba9ca02dc --- /dev/null +++ b/support/xpthread_sigmask.c @@ -0,0 +1,34 @@ +/* pthread_sigmask with error checking. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include + +#include + +void +xpthread_sigmask (int how, const sigset_t *set, sigset_t *oldset) +{ + if (pthread_sigmask (how, set, oldset) != 0) + { + write_message ("error: pthread_setmask failed\n"); + /* Do not use exit because pthread_sigmask can be called from a + signal handler. */ + _exit (1); + } +} diff --git a/support/xpthread_spin_lock.c b/support/xpthread_spin_lock.c new file mode 100644 index 0000000000..6975215b17 --- /dev/null +++ b/support/xpthread_spin_lock.c @@ -0,0 +1,25 @@ +/* pthread_spin_lock with error checking. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +void +xpthread_spin_lock (pthread_spinlock_t *lock) +{ + xpthread_check_return ("pthread_spin_lock", pthread_spin_lock (lock)); +} diff --git a/support/xpthread_spin_unlock.c b/support/xpthread_spin_unlock.c new file mode 100644 index 0000000000..4f19a44c48 --- /dev/null +++ b/support/xpthread_spin_unlock.c @@ -0,0 +1,25 @@ +/* pthread_spin_unlock with error checking. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +void +xpthread_spin_unlock (pthread_spinlock_t *lock) +{ + xpthread_check_return ("pthread_spin_unlock", pthread_spin_unlock (lock)); +} diff --git a/support/xrealloc.c b/support/xrealloc.c new file mode 100644 index 0000000000..00c313880c --- /dev/null +++ b/support/xrealloc.c @@ -0,0 +1,32 @@ +/* Error-checking wrapper for realloc. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include + +void * +xrealloc (void *p, size_t n) +{ + void *result = realloc (p, n); + if (result == NULL && (n > 0 || p == NULL)) + oom_error ("realloc", n); + return result; +} diff --git a/support/xrecvfrom.c b/support/xrecvfrom.c new file mode 100644 index 0000000000..17809c4dd2 --- /dev/null +++ b/support/xrecvfrom.c @@ -0,0 +1,33 @@ +/* recvfrom with error checking. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include + +size_t +xrecvfrom (int fd, void *buf, size_t buflen, int flags, + struct sockaddr *sa, socklen_t *salen) +{ + ssize_t ret = recvfrom (fd, buf, buflen, flags, sa, salen); + if (ret < 0) + FAIL_EXIT1 ("error: recvfrom (%d), %zu bytes buffer: %m", fd, buflen); + return ret; +} diff --git a/support/xsendto.c b/support/xsendto.c new file mode 100644 index 0000000000..20bddf6965 --- /dev/null +++ b/support/xsendto.c @@ -0,0 +1,35 @@ +/* sendto with error checking. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include + +void +xsendto (int fd, const void *buf, size_t buflen, int flags, + const struct sockaddr *sa, socklen_t salen) +{ + ssize_t ret = sendto (fd, buf, buflen, flags, sa, salen); + if (ret < 0) + FAIL_EXIT1 ("sendto (%d), %zu bytes, family %d: %m", + fd, buflen, sa->sa_family); + if (ret != buflen) + FAIL_EXIT1 ("sendto (%d) sent %zd bytes instead of %zu", fd, ret, buflen); +} diff --git a/sysdeps/sparc/sparc32/fpu/s_fdimf.S b/support/xsetsockopt.c similarity index 62% rename from sysdeps/sparc/sparc32/fpu/s_fdimf.S rename to support/xsetsockopt.c index c3fe8afa98..9931882e75 100644 --- a/sysdeps/sparc/sparc32/fpu/s_fdimf.S +++ b/support/xsetsockopt.c @@ -1,7 +1,6 @@ -/* Compute positive difference, sparc 32-bit. - Copyright (C) 2013-2016 Free Software Foundation, Inc. +/* setsockopt with error checking. + Copyright (C) 2016-2017 Free Software Foundation, Inc. This file is part of the GNU C Library. - Contributed by David S. Miller . The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -17,19 +16,16 @@ License along with the GNU C Library; if not, see . */ -#include +#include -ENTRY(__fdimf) - st %o0, [%sp + 72] - st %o1, [%sp + 76] - ld [%sp + 72], %f0 - ld [%sp + 76], %f1 - fcmps %f0, %f1 - fbug 1f - st %g0, [%sp + 72] - ld [%sp + 72], %f0 - fnegs %f0, %f1 -1: retl - fsubs %f0, %f1, %f0 -END(__fdimf) -weak_alias (__fdimf, fdimf) +#include +#include +#include + +void +xsetsockopt (int fd, int level, int name, const void *val, socklen_t vallen) +{ + if (setsockopt (fd, level, name, val, vallen) != 0) + FAIL_EXIT1 ("setsockopt (%d, %d, %d), %zu bytes: %m", + fd, level, name, (size_t) vallen); +} diff --git a/support/xsignal.h b/support/xsignal.h new file mode 100644 index 0000000000..3dc0d9d5ce --- /dev/null +++ b/support/xsignal.h @@ -0,0 +1,34 @@ +/* Support functionality for using signals. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef SUPPORT_SIGNAL_H +#define SUPPORT_SIGNAL_H + +#include +#include + +__BEGIN_DECLS + +/* The following functions call the corresponding libpthread functions + and terminate the process on error. */ + +void xpthread_sigmask (int how, const sigset_t *set, sigset_t *oldset); + +__END_DECLS + +#endif /* SUPPORT_SIGNAL_H */ diff --git a/support/xsocket.c b/support/xsocket.c new file mode 100644 index 0000000000..c1deaee924 --- /dev/null +++ b/support/xsocket.c @@ -0,0 +1,32 @@ +/* socket with error checking. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include + +int +xsocket (int domain, int type, int protocol) +{ + int fd = socket (domain, type, protocol); + if (fd < 0) + FAIL_EXIT1 ("socket (%d, %d, %d): %m\n", domain, type, protocol); + return fd; +} diff --git a/support/xsocket.h b/support/xsocket.h new file mode 100644 index 0000000000..d6724948d8 --- /dev/null +++ b/support/xsocket.h @@ -0,0 +1,39 @@ +/* Error-checking wrappers for socket functions. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef SUPPORT_XSOCKET_H +#define SUPPORT_XSOCKET_H + +#include +#include +#include + +int xsocket (int, int, int); +void xsetsockopt (int, int, int, const void *, socklen_t); +void xgetsockname (int, struct sockaddr *, socklen_t *); +void xconnect (int, const struct sockaddr *, socklen_t); +void xbind (int, const struct sockaddr *, socklen_t); +void xlisten (int, int); +int xaccept (int, struct sockaddr *, socklen_t *); +int xaccept4 (int, struct sockaddr *, socklen_t *, int); +void xsendto (int, const void *, size_t, int, + const struct sockaddr *, socklen_t); +size_t xrecvfrom (int, void *, size_t, int, struct sockaddr *, socklen_t *); +int xpoll (struct pollfd *, nfds_t, int); + +#endif /* SUPPORT_XSOCKET_H */ diff --git a/support/xstdio.h b/support/xstdio.h new file mode 100644 index 0000000000..bcc2e863bf --- /dev/null +++ b/support/xstdio.h @@ -0,0 +1,32 @@ +/* Error-checking wrappers for stdio functions. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef SUPPORT_XSTDIO_H +#define SUPPORT_XSTDIO_H + +#include +#include + +__BEGIN_DECLS + +FILE *xfopen (const char *path, const char *mode); +void xfclose (FILE *); + +__END_DECLS + +#endif /* SUPPORT_XSTDIO_H */ diff --git a/support/xstrdup.c b/support/xstrdup.c new file mode 100644 index 0000000000..d6a8c04baf --- /dev/null +++ b/support/xstrdup.c @@ -0,0 +1,30 @@ +/* strdup with error checking. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include + +char * +xstrdup (const char *s) +{ + char *p = strdup (s); + if (p == NULL) + oom_error ("strdup", strlen (s)); + return p; +} diff --git a/support/xthread.h b/support/xthread.h new file mode 100644 index 0000000000..6dd7e709be --- /dev/null +++ b/support/xthread.h @@ -0,0 +1,77 @@ +/* Support functionality for using threads. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef SUPPORT_THREAD_H +#define SUPPORT_THREAD_H + +#include +#include + +__BEGIN_DECLS + +/* Terminate the process (with exit status 0) after SECONDS have + elapsed, from a helper thread. The process is terminated with the + exit function, so atexit handlers are executed. */ +void delayed_exit (int seconds); + +/* Terminate the process (with exit status 1) if VALUE is not zero. + In that case, print a failure message to standard output mentioning + FUNCTION. The process is terminated with the exit function, so + atexit handlers are executed. */ +void xpthread_check_return (const char *function, int value); + +/* The following functions call the corresponding libpthread functions + and terminate the process on error. */ + +void xpthread_barrier_init (pthread_barrier_t *barrier, + pthread_barrierattr_t *attr, unsigned int count); +void xpthread_barrier_destroy (pthread_barrier_t *barrier); +void xpthread_mutexattr_destroy (pthread_mutexattr_t *); +void xpthread_mutexattr_init (pthread_mutexattr_t *); +void xpthread_mutexattr_setprotocol (pthread_mutexattr_t *, int); +void xpthread_mutexattr_setpshared (pthread_mutexattr_t *, int); +void xpthread_mutexattr_setrobust (pthread_mutexattr_t *, int); +void xpthread_mutexattr_settype (pthread_mutexattr_t *, int); +void xpthread_mutex_init (pthread_mutex_t *, const pthread_mutexattr_t *); +void xpthread_mutex_destroy (pthread_mutex_t *); +void xpthread_mutex_lock (pthread_mutex_t *mutex); +void xpthread_mutex_unlock (pthread_mutex_t *mutex); +void xpthread_mutex_consistent (pthread_mutex_t *); +void xpthread_spin_lock (pthread_spinlock_t *lock); +void xpthread_spin_unlock (pthread_spinlock_t *lock); +void xpthread_cond_wait (pthread_cond_t * cond, pthread_mutex_t * mutex); +pthread_t xpthread_create (pthread_attr_t *attr, + void *(*thread_func) (void *), void *closure); +void xpthread_detach (pthread_t thr); +void xpthread_cancel (pthread_t thr); +void *xpthread_join (pthread_t thr); +void xpthread_once (pthread_once_t *guard, void (*func) (void)); +void xpthread_attr_destroy (pthread_attr_t *attr); +void xpthread_attr_init (pthread_attr_t *attr); +void xpthread_attr_setdetachstate (pthread_attr_t *attr, + int detachstate); +void xpthread_attr_setstacksize (pthread_attr_t *attr, + size_t stacksize); + +/* This function returns non-zero if pthread_barrier_wait returned + PTHREAD_BARRIER_SERIAL_THREAD. */ +int xpthread_barrier_wait (pthread_barrier_t *barrier); + +__END_DECLS + +#endif /* SUPPORT_THREAD_H */ diff --git a/support/xunistd.h b/support/xunistd.h new file mode 100644 index 0000000000..151d743e1f --- /dev/null +++ b/support/xunistd.h @@ -0,0 +1,56 @@ +/* POSIX-specific extra functions. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +/* These wrapper functions use POSIX types and therefore cannot be + declared in . */ + +#ifndef SUPPORT_XUNISTD_H +#define SUPPORT_XUNISTD_H + +#include +#include +#include + +__BEGIN_DECLS + +struct stat64; + +pid_t xfork (void); +pid_t xwaitpid (pid_t, int *status, int flags); +void xpipe (int[2]); +void xdup2 (int, int); +int xopen (const char *path, int flags, mode_t); +void xstat (const char *path, struct stat64 *); +void xmkdir (const char *path, mode_t); +void xchroot (const char *path); + +/* Close the file descriptor. Ignore EINTR errors, but terminate the + process on other errors. */ +void xclose (int); + +/* Write the buffer. Retry on short writes. */ +void xwrite (int, const void *, size_t); + +/* Invoke mmap with a zero file offset. */ +void *xmmap (void *addr, size_t length, int prot, int flags, int fd); + +void xmunmap (void *addr, size_t length); + +__END_DECLS + +#endif /* SUPPORT_XUNISTD_H */ diff --git a/support/xwaitpid.c b/support/xwaitpid.c new file mode 100644 index 0000000000..204795e4c0 --- /dev/null +++ b/support/xwaitpid.c @@ -0,0 +1,33 @@ +/* waitpid with error checking. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include +#include + +int +xwaitpid (int pid, int *status, int flags) +{ + pid_t result = waitpid (pid, status, flags); + if (result < 0) + FAIL_EXIT1 ("waitpid: %m\n"); + return result; +} diff --git a/support/xwrite.c b/support/xwrite.c new file mode 100644 index 0000000000..134e8ee4c1 --- /dev/null +++ b/support/xwrite.c @@ -0,0 +1,39 @@ +/* write with error checking and retries. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include + +void +xwrite (int fd, const void *buffer, size_t length) +{ + const char *p = buffer; + const char *end = p + length; + while (p < end) + { + ssize_t ret = write (fd, p, end - p); + if (ret < 0) + FAIL_EXIT1 ("write of %zu bytes failed after %td: %m", + length, p - (const char *) buffer); + if (ret == 0) + FAIL_EXIT1 ("write return 0 after writing %td bytes of %zu", + p - (const char *) buffer, length); + p += ret; + } +} diff --git a/sysdeps/aarch64/dl-machine.h b/sysdeps/aarch64/dl-machine.h index 282805e396..e86d8b5b63 100644 --- a/sysdeps/aarch64/dl-machine.h +++ b/sysdeps/aarch64/dl-machine.h @@ -172,8 +172,8 @@ _dl_start_user: \n\ cmp x0, #0 \n\ bne 1b \n\ // Update _dl_argv \n\ - adrp x3, _dl_argv \n\ - str x2, [x3, #:lo12:_dl_argv] \n\ + adrp x3, __GI__dl_argv \n\ + str x2, [x3, #:lo12:__GI__dl_argv] \n\ .L_done_stack_adjust: \n\ // compute envp \n\ add x3, x2, x1, lsl #3 \n\ diff --git a/sysdeps/aarch64/nptl/tcb-offsets.sym b/sysdeps/aarch64/nptl/tcb-offsets.sym index 0677aeabff..238647dd47 100644 --- a/sysdeps/aarch64/nptl/tcb-offsets.sym +++ b/sysdeps/aarch64/nptl/tcb-offsets.sym @@ -2,6 +2,5 @@ #include PTHREAD_MULTIPLE_THREADS_OFFSET offsetof (struct pthread, header.multiple_threads) -PTHREAD_PID_OFFSET offsetof (struct pthread, pid) PTHREAD_TID_OFFSET offsetof (struct pthread, tid) PTHREAD_SIZEOF sizeof (struct pthread) diff --git a/sysdeps/alpha/fpu/s_ceil.c b/sysdeps/alpha/fpu/s_ceil.c index c1ff864d4b..e9c350af1c 100644 --- a/sysdeps/alpha/fpu/s_ceil.c +++ b/sysdeps/alpha/fpu/s_ceil.c @@ -26,17 +26,16 @@ double __ceil (double x) { + if (isnan (x)) + return x + x; + if (isless (fabs (x), 9007199254740992.0)) /* 1 << DBL_MANT_DIG */ { double tmp1, new_x; new_x = -x; __asm ( -#ifdef _IEEE_FP_INEXACT - "cvttq/svim %2,%1\n\t" -#else "cvttq/svm %2,%1\n\t" -#endif "cvtqt/m %1,%0\n\t" : "=f"(new_x), "=&f"(tmp1) : "f"(new_x)); diff --git a/sysdeps/alpha/fpu/s_ceilf.c b/sysdeps/alpha/fpu/s_ceilf.c index 7e63a6fe94..77e01a99f7 100644 --- a/sysdeps/alpha/fpu/s_ceilf.c +++ b/sysdeps/alpha/fpu/s_ceilf.c @@ -25,6 +25,9 @@ float __ceilf (float x) { + if (isnanf (x)) + return x + x; + if (isless (fabsf (x), 16777216.0f)) /* 1 << FLT_MANT_DIG */ { /* Note that Alpha S_Floating is stored in registers in a @@ -36,11 +39,7 @@ __ceilf (float x) new_x = -x; __asm ("cvtst/s %3,%2\n\t" -#ifdef _IEEE_FP_INEXACT - "cvttq/svim %2,%1\n\t" -#else "cvttq/svm %2,%1\n\t" -#endif "cvtqt/m %1,%0\n\t" : "=f"(new_x), "=&f"(tmp1), "=&f"(tmp2) : "f"(new_x)); diff --git a/sysdeps/alpha/fpu/s_floor.c b/sysdeps/alpha/fpu/s_floor.c index 1a6f8c4617..9930f6be42 100644 --- a/sysdeps/alpha/fpu/s_floor.c +++ b/sysdeps/alpha/fpu/s_floor.c @@ -27,16 +27,15 @@ double __floor (double x) { + if (isnan (x)) + return x + x; + if (isless (fabs (x), 9007199254740992.0)) /* 1 << DBL_MANT_DIG */ { double tmp1, new_x; __asm ( -#ifdef _IEEE_FP_INEXACT - "cvttq/svim %2,%1\n\t" -#else "cvttq/svm %2,%1\n\t" -#endif "cvtqt/m %1,%0\n\t" : "=f"(new_x), "=&f"(tmp1) : "f"(x)); diff --git a/sysdeps/alpha/fpu/s_floorf.c b/sysdeps/alpha/fpu/s_floorf.c index 8cd80e2b42..015c04f40d 100644 --- a/sysdeps/alpha/fpu/s_floorf.c +++ b/sysdeps/alpha/fpu/s_floorf.c @@ -26,6 +26,9 @@ float __floorf (float x) { + if (isnanf (x)) + return x + x; + if (isless (fabsf (x), 16777216.0f)) /* 1 << FLT_MANT_DIG */ { /* Note that Alpha S_Floating is stored in registers in a @@ -36,11 +39,7 @@ __floorf (float x) float tmp1, tmp2, new_x; __asm ("cvtst/s %3,%2\n\t" -#ifdef _IEEE_FP_INEXACT - "cvttq/svim %2,%1\n\t" -#else "cvttq/svm %2,%1\n\t" -#endif "cvtqt/m %1,%0\n\t" : "=f"(new_x), "=&f"(tmp1), "=&f"(tmp2) : "f"(x)); diff --git a/sysdeps/alpha/fpu/s_rint.c b/sysdeps/alpha/fpu/s_rint.c index f33fe72c11..259348afc0 100644 --- a/sysdeps/alpha/fpu/s_rint.c +++ b/sysdeps/alpha/fpu/s_rint.c @@ -23,6 +23,9 @@ double __rint (double x) { + if (isnan (x)) + return x + x; + if (isless (fabs (x), 9007199254740992.0)) /* 1 << DBL_MANT_DIG */ { double tmp1, new_x; diff --git a/sysdeps/alpha/fpu/s_rintf.c b/sysdeps/alpha/fpu/s_rintf.c index 1400dfe8d7..645728ad5b 100644 --- a/sysdeps/alpha/fpu/s_rintf.c +++ b/sysdeps/alpha/fpu/s_rintf.c @@ -22,6 +22,9 @@ float __rintf (float x) { + if (isnanf (x)) + return x + x; + if (isless (fabsf (x), 16777216.0f)) /* 1 << FLT_MANT_DIG */ { /* Note that Alpha S_Floating is stored in registers in a diff --git a/sysdeps/alpha/fpu/s_trunc.c b/sysdeps/alpha/fpu/s_trunc.c index 16cb114a72..4b986a6926 100644 --- a/sysdeps/alpha/fpu/s_trunc.c +++ b/sysdeps/alpha/fpu/s_trunc.c @@ -28,12 +28,11 @@ __trunc (double x) double two52 = copysign (0x1.0p52, x); double r, tmp; + if (isgreaterequal (fabs (x), 0x1.0p52)) + return x; + __asm ( -#ifdef _IEEE_FP_INEXACT - "addt/suic %2, %3, %1\n\tsubt/suic %1, %3, %0" -#else "addt/suc %2, %3, %1\n\tsubt/suc %1, %3, %0" -#endif : "=&f"(r), "=&f"(tmp) : "f"(x), "f"(two52)); diff --git a/sysdeps/alpha/fpu/s_truncf.c b/sysdeps/alpha/fpu/s_truncf.c index 2290f28295..3e93356166 100644 --- a/sysdeps/alpha/fpu/s_truncf.c +++ b/sysdeps/alpha/fpu/s_truncf.c @@ -27,12 +27,11 @@ __truncf (float x) float two23 = copysignf (0x1.0p23, x); float r, tmp; + if (isgreaterequal (fabsf (x), 0x1.0p23)) + return x; + __asm ( -#ifdef _IEEE_FP_INEXACT - "adds/suic %2, %3, %1\n\tsubs/suic %1, %3, %0" -#else "adds/suc %2, %3, %1\n\tsubs/suc %1, %3, %0" -#endif : "=&f"(r), "=&f"(tmp) : "f"(x), "f"(two23)); diff --git a/sysdeps/alpha/nptl/tcb-offsets.sym b/sysdeps/alpha/nptl/tcb-offsets.sym index c21a791040..1005621b37 100644 --- a/sysdeps/alpha/nptl/tcb-offsets.sym +++ b/sysdeps/alpha/nptl/tcb-offsets.sym @@ -10,5 +10,4 @@ #define thread_offsetof(mem) (long)(offsetof(struct pthread, mem) - sizeof(struct pthread)) MULTIPLE_THREADS_OFFSET thread_offsetof (header.multiple_threads) -PID_OFFSET thread_offsetof (pid) TID_OFFSET thread_offsetof (tid) diff --git a/sysdeps/arm/nacl/libc.abilist b/sysdeps/arm/nacl/libc.abilist index 2f7751d167..dfa7198306 100644 --- a/sysdeps/arm/nacl/libc.abilist +++ b/sysdeps/arm/nacl/libc.abilist @@ -1840,4 +1840,5 @@ GLIBC_2.23 fts64_close F GLIBC_2.23 fts64_open F GLIBC_2.23 fts64_read F GLIBC_2.23 fts64_set F +GLIBC_2.24 GLIBC_2.24 A GLIBC_2.24 quick_exit F diff --git a/sysdeps/arm/nptl/tcb-offsets.sym b/sysdeps/arm/nptl/tcb-offsets.sym index 92cc441d3d..bf9c0a1c17 100644 --- a/sysdeps/arm/nptl/tcb-offsets.sym +++ b/sysdeps/arm/nptl/tcb-offsets.sym @@ -7,5 +7,4 @@ #define thread_offsetof(mem) (long)(offsetof(struct pthread, mem) - sizeof(struct pthread)) MULTIPLE_THREADS_OFFSET thread_offsetof (header.multiple_threads) -PID_OFFSET thread_offsetof (pid) TID_OFFSET thread_offsetof (tid) diff --git a/sysdeps/generic/unsecvars.h b/sysdeps/generic/unsecvars.h index d5b8119c9c..ac57bd5db0 100644 --- a/sysdeps/generic/unsecvars.h +++ b/sysdeps/generic/unsecvars.h @@ -4,11 +4,13 @@ #define UNSECURE_ENVVARS \ "GCONV_PATH\0" \ "GETCONF_DIR\0" \ + "GLIBC_TUNABLES\0" \ "HOSTALIASES\0" \ "LD_AUDIT\0" \ "LD_DEBUG\0" \ "LD_DEBUG_OUTPUT\0" \ "LD_DYNAMIC_WEAK\0" \ + "LD_HWCAP_MASK\0" \ "LD_LIBRARY_PATH\0" \ "LD_ORIGIN_PATH\0" \ "LD_PRELOAD\0" \ diff --git a/sysdeps/gnu/glob64.c b/sysdeps/gnu/glob64.c index d1e4e6f0d5..52e97e2f6a 100644 --- a/sysdeps/gnu/glob64.c +++ b/sysdeps/gnu/glob64.c @@ -15,11 +15,8 @@ #undef __stat #define __stat(file, buf) __xstat64 (_STAT_VER, file, buf) -#define NO_GLOB_PATTERN_P 1 - #define COMPILE_GLOB64 1 #include libc_hidden_def (glob64) -libc_hidden_def (globfree64) diff --git a/sysdeps/gnu/globfree64.c b/sysdeps/gnu/globfree64.c new file mode 100644 index 0000000000..f092d0bf8b --- /dev/null +++ b/sysdeps/gnu/globfree64.c @@ -0,0 +1,10 @@ +#include +#include +#include + +#define glob_t glob64_t +#define globfree(pglob) globfree64 (pglob) + +#include + +libc_hidden_def (globfree64) diff --git a/sysdeps/hppa/dl-machine.h b/sysdeps/hppa/dl-machine.h index 9404211819..01bd5bf197 100644 --- a/sysdeps/hppa/dl-machine.h +++ b/sysdeps/hppa/dl-machine.h @@ -302,6 +302,10 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) #define ARCH_LA_PLTENTER hppa_gnu_pltenter #define ARCH_LA_PLTEXIT hppa_gnu_pltexit +/* Adjust DL_STACK_END to get value we want in __libc_stack_end. */ +#define DL_STACK_END(cookie) \ + ((void *) (((long) (cookie)) + 0x160)) + /* Initial entry point code for the dynamic linker. The C function `_dl_start' is the real entry point; its return value is the user program's entry point. */ @@ -401,11 +405,6 @@ asm ( \ /* Save the entry point in %r3. */ \ " copy %ret0,%r3\n" \ \ - /* Remember the lowest stack address. */ \ -" addil LT'__libc_stack_end,%r19\n" \ -" ldw RT'__libc_stack_end(%r1),%r20\n" \ -" stw %sp,0(%r20)\n" \ - \ /* See if we were called as a command with the executable file \ name as an extra leading argument. */ \ " addil LT'_dl_skip_args,%r19\n" \ diff --git a/sysdeps/hppa/nptl/tcb-offsets.sym b/sysdeps/hppa/nptl/tcb-offsets.sym index c2f326ee3d..6e852f35b1 100644 --- a/sysdeps/hppa/nptl/tcb-offsets.sym +++ b/sysdeps/hppa/nptl/tcb-offsets.sym @@ -3,7 +3,6 @@ RESULT offsetof (struct pthread, result) TID offsetof (struct pthread, tid) -PID offsetof (struct pthread, pid) CANCELHANDLING offsetof (struct pthread, cancelhandling) CLEANUP_JMP_BUF offsetof (struct pthread, cleanup_jmp_buf) MULTIPLE_THREADS_OFFSET offsetof (struct pthread, header.multiple_threads) @@ -14,6 +13,5 @@ MUTEX_FUTEX offsetof (pthread_mutex_t, __data.__lock) -- This way we get the offset of a member in the struct pthread that -- preceeds the thread pointer (which points to the dtv). #define thread_offsetof(mem) (unsigned int)(offsetof(struct pthread, mem) - sizeof(struct pthread)) -PID_THREAD_OFFSET thread_offsetof (pid) TID_THREAD_OFFSET thread_offsetof (tid) MULTIPLE_THREADS_THREAD_OFFSET thread_offsetof (header.multiple_threads) diff --git a/sysdeps/i386/i686/multiarch/strcspn-c.c b/sysdeps/i386/i686/multiarch/strcspn-c.c index 6d61e190a8..ec230fb383 100644 --- a/sysdeps/i386/i686/multiarch/strcspn-c.c +++ b/sysdeps/i386/i686/multiarch/strcspn-c.c @@ -1,2 +1,4 @@ -#define __strcspn_sse2 __strcspn_ia32 -#include +#if IS_IN (libc) +# define __strcspn_sse2 __strcspn_ia32 +# include +#endif diff --git a/sysdeps/i386/i686/multiarch/varshift.c b/sysdeps/i386/i686/multiarch/varshift.c index 7760b966e2..6742a35d41 100644 --- a/sysdeps/i386/i686/multiarch/varshift.c +++ b/sysdeps/i386/i686/multiarch/varshift.c @@ -1 +1,3 @@ -#include +#if IS_IN (libc) +# include +#endif diff --git a/sysdeps/i386/nptl/tcb-offsets.sym b/sysdeps/i386/nptl/tcb-offsets.sym index 7bdf161b29..695a810386 100644 --- a/sysdeps/i386/nptl/tcb-offsets.sym +++ b/sysdeps/i386/nptl/tcb-offsets.sym @@ -4,7 +4,6 @@ RESULT offsetof (struct pthread, result) TID offsetof (struct pthread, tid) -PID offsetof (struct pthread, pid) CANCELHANDLING offsetof (struct pthread, cancelhandling) CLEANUP_JMP_BUF offsetof (struct pthread, cleanup_jmp_buf) MULTIPLE_THREADS_OFFSET offsetof (tcbhead_t, multiple_threads) diff --git a/sysdeps/ia64/nptl/Makefile b/sysdeps/ia64/nptl/Makefile index 48f1327446..1e6be8eea8 100644 --- a/sysdeps/ia64/nptl/Makefile +++ b/sysdeps/ia64/nptl/Makefile @@ -21,4 +21,5 @@ endif ifeq ($(subdir),nptl) libpthread-routines += ptw-sysdep ptw-sigblock ptw-sigprocmask +libpthread-shared-only-routines += ptw-sysdep ptw-sigblock ptw-sigprocmask endif diff --git a/sysdeps/ia64/nptl/tcb-offsets.sym b/sysdeps/ia64/nptl/tcb-offsets.sym index e1707ab1c8..b01f712be2 100644 --- a/sysdeps/ia64/nptl/tcb-offsets.sym +++ b/sysdeps/ia64/nptl/tcb-offsets.sym @@ -1,7 +1,6 @@ #include #include -PID offsetof (struct pthread, pid) - TLS_PRE_TCB_SIZE TID offsetof (struct pthread, tid) - TLS_PRE_TCB_SIZE MULTIPLE_THREADS_OFFSET offsetof (struct pthread, header.multiple_threads) - TLS_PRE_TCB_SIZE SYSINFO_OFFSET offsetof (tcbhead_t, __private) diff --git a/sysdeps/ieee754/dbl-64/e_pow.c b/sysdeps/ieee754/dbl-64/e_pow.c index 663fa392c2..bd758b5979 100644 --- a/sysdeps/ieee754/dbl-64/e_pow.c +++ b/sysdeps/ieee754/dbl-64/e_pow.c @@ -466,15 +466,15 @@ checkint (double x) return (n & 1) ? -1 : 1; /* odd or even */ if (k > 20) { - if (n << (k - 20)) + if (n << (k - 20) != 0) return 0; /* if not integer */ - return (n << (k - 21)) ? -1 : 1; + return (n << (k - 21) != 0) ? -1 : 1; } if (n) return 0; /*if not integer */ if (k == 20) return (m & 1) ? -1 : 1; - if (m << (k + 12)) + if (m << (k + 12) != 0) return 0; - return (m << (k + 11)) ? -1 : 1; + return (m << (k + 11) != 0) ? -1 : 1; } diff --git a/sysdeps/m68k/m680x0/m68020/atomic-machine.h b/sysdeps/m68k/m680x0/m68020/atomic-machine.h index 24bc5c5ef7..65965cca9e 100644 --- a/sysdeps/m68k/m680x0/m68020/atomic-machine.h +++ b/sysdeps/m68k/m680x0/m68020/atomic-machine.h @@ -73,7 +73,7 @@ typedef uintmax_t uatomic_max_t; __typeof (mem) __memp = (mem); \ __asm __volatile ("cas2%.l %0:%R0,%1:%R1,(%2):(%3)" \ : "=d" (__ret) \ - : "d" (newval), "r" (__memp), \ + : "d" ((__typeof (*(mem))) (newval)), "r" (__memp), \ "r" ((char *) __memp + 4), "0" (oldval) \ : "memory"); \ __ret; }) @@ -101,8 +101,9 @@ typedef uintmax_t uatomic_max_t; __asm __volatile ("1: cas2%.l %0:%R0,%1:%R1,(%2):(%3);" \ " jbne 1b" \ : "=d" (__result) \ - : "d" (newvalue), "r" (__memp), \ - "r" ((char *) __memp + 4), "0" (__result) \ + : "d" ((__typeof (*(mem))) (newvalue)), \ + "r" (__memp), "r" ((char *) __memp + 4), \ + "0" (__result) \ : "memory"); \ } \ __result; }) @@ -144,7 +145,7 @@ typedef uintmax_t uatomic_max_t; " cas2%.l %0:%R0,%1:%R1,(%3):(%4);" \ " jbne 1b" \ : "=d" (__result), "=&d" (__temp) \ - : "d" (value), "r" (__memp), \ + : "d" ((__typeof (*(mem))) (value)), "r" (__memp), \ "r" ((char *) __memp + 4), "0" (__result) \ : "memory"); \ } \ @@ -175,8 +176,9 @@ typedef uintmax_t uatomic_max_t; " cas2%.l %0:%R0,%1:%R1,(%3):(%4);" \ " jbne 1b" \ : "=d" (__oldval), "=&d" (__temp) \ - : "d" (value), "r" (__memp), \ - "r" ((char *) __memp + 4), "0" (__oldval) \ + : "d" ((__typeof (*(mem))) (value)), \ + "r" (__memp), "r" ((char *) __memp + 4), \ + "0" (__oldval) \ : "memory"); \ } \ }) diff --git a/sysdeps/m68k/nptl/tcb-offsets.sym b/sysdeps/m68k/nptl/tcb-offsets.sym index b1bba65868..241fb8b47c 100644 --- a/sysdeps/m68k/nptl/tcb-offsets.sym +++ b/sysdeps/m68k/nptl/tcb-offsets.sym @@ -7,5 +7,4 @@ #define thread_offsetof(mem) (long)(offsetof(struct pthread, mem) - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE) MULTIPLE_THREADS_OFFSET thread_offsetof (header.multiple_threads) -PID_OFFSET thread_offsetof (pid) TID_OFFSET thread_offsetof (tid) diff --git a/sysdeps/microblaze/nptl/tcb-offsets.sym b/sysdeps/microblaze/nptl/tcb-offsets.sym index 18afbee291..614f0dfed6 100644 --- a/sysdeps/microblaze/nptl/tcb-offsets.sym +++ b/sysdeps/microblaze/nptl/tcb-offsets.sym @@ -7,5 +7,4 @@ #define thread_offsetof(mem) (long)(offsetof (struct pthread, mem) - sizeof (struct pthread)) MULTIPLE_THREADS_OFFSET thread_offsetof (header.multiple_threads) -PID_OFFSET thread_offsetof (pid) TID_OFFSET thread_offsetof (tid) diff --git a/sysdeps/mips/Makefile b/sysdeps/mips/Makefile index 3d3552322b..7c1d77941e 100644 --- a/sysdeps/mips/Makefile +++ b/sysdeps/mips/Makefile @@ -9,6 +9,7 @@ endif ifeq ($(subdir),rt) librt-sysdep_routines += rt-sysdep +librt-shared-only-routines += rt-sysdep endif ifeq ($(subdir),debug) diff --git a/sysdeps/mips/mips32/crti.S b/sysdeps/mips/mips32/crti.S index 5c0ad7328a..dfbbdc4f8f 100644 --- a/sysdeps/mips/mips32/crti.S +++ b/sysdeps/mips/mips32/crti.S @@ -74,6 +74,7 @@ _init: .reloc 1f,R_MIPS_JALR,PREINIT_FUNCTION 1: jalr $25 .Lno_weak_fn: + .insn #else lw $25,%got(PREINIT_FUNCTION)($28) .reloc 1f,R_MIPS_JALR,PREINIT_FUNCTION diff --git a/sysdeps/mips/mips64/n32/crti.S b/sysdeps/mips/mips64/n32/crti.S index 00b89f3894..afe6d8edaa 100644 --- a/sysdeps/mips/mips64/n32/crti.S +++ b/sysdeps/mips/mips64/n32/crti.S @@ -74,6 +74,7 @@ _init: .reloc 1f,R_MIPS_JALR,PREINIT_FUNCTION 1: jalr $25 .Lno_weak_fn: + .insn #else lw $25,%got_disp(PREINIT_FUNCTION)($28) .reloc 1f,R_MIPS_JALR,PREINIT_FUNCTION diff --git a/sysdeps/mips/mips64/n64/crti.S b/sysdeps/mips/mips64/n64/crti.S index f59b20c631..4049d29290 100644 --- a/sysdeps/mips/mips64/n64/crti.S +++ b/sysdeps/mips/mips64/n64/crti.S @@ -74,6 +74,7 @@ _init: .reloc 1f,R_MIPS_JALR,PREINIT_FUNCTION 1: jalr $25 .Lno_weak_fn: + .insn #else ld $25,%got_disp(PREINIT_FUNCTION)($28) .reloc 1f,R_MIPS_JALR,PREINIT_FUNCTION diff --git a/sysdeps/mips/nptl/Makefile b/sysdeps/mips/nptl/Makefile index 117744ffe2..dda154d842 100644 --- a/sysdeps/mips/nptl/Makefile +++ b/sysdeps/mips/nptl/Makefile @@ -21,4 +21,5 @@ endif ifeq ($(subdir),nptl) libpthread-sysdep_routines += nptl-sysdep +libpthread-shared-only-routines += nptl-sysdep endif diff --git a/sysdeps/mips/nptl/tcb-offsets.sym b/sysdeps/mips/nptl/tcb-offsets.sym index e0e71dc430..9ea25b94a8 100644 --- a/sysdeps/mips/nptl/tcb-offsets.sym +++ b/sysdeps/mips/nptl/tcb-offsets.sym @@ -7,5 +7,4 @@ #define thread_offsetof(mem) (long)(offsetof(struct pthread, mem) - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE) MULTIPLE_THREADS_OFFSET thread_offsetof (header.multiple_threads) -PID_OFFSET thread_offsetof (pid) TID_OFFSET thread_offsetof (tid) diff --git a/sysdeps/nacl/clock.c b/sysdeps/nacl/clock.c index 664ad650c3..b6fbcfd2dd 100644 --- a/sysdeps/nacl/clock.c +++ b/sysdeps/nacl/clock.c @@ -24,6 +24,6 @@ clock_t clock (void) { - nacl_abi_clock_t result; + nacl_irt_clock_t result; return NACL_CALL (__nacl_irt_basic.clock (&result), result); } diff --git a/sysdeps/nacl/dup.c b/sysdeps/nacl/dup.c index 34a7cd46d4..cbce3f5a5a 100644 --- a/sysdeps/nacl/dup.c +++ b/sysdeps/nacl/dup.c @@ -27,4 +27,5 @@ __dup (int fd) int result; return NACL_CALL (__nacl_irt_fdio.dup (fd, &result), result); } +libc_hidden_def (__dup) weak_alias (__dup, dup) diff --git a/sysdeps/nios2/nptl/tcb-offsets.sym b/sysdeps/nios2/nptl/tcb-offsets.sym index d9ae952585..3cd8d984ac 100644 --- a/sysdeps/nios2/nptl/tcb-offsets.sym +++ b/sysdeps/nios2/nptl/tcb-offsets.sym @@ -9,6 +9,5 @@ # define thread_offsetof(mem) ((ptrdiff_t) THREAD_SELF + offsetof (struct pthread, mem)) MULTIPLE_THREADS_OFFSET thread_offsetof (header.multiple_threads) -PID_OFFSET thread_offsetof (pid) TID_OFFSET thread_offsetof (tid) POINTER_GUARD (offsetof (tcbhead_t, pointer_guard) - TLS_TCB_OFFSET - sizeof (tcbhead_t)) diff --git a/sysdeps/nptl/fork.c b/sysdeps/nptl/fork.c index 616d897a36..a5d1e86d71 100644 --- a/sysdeps/nptl/fork.c +++ b/sysdeps/nptl/fork.c @@ -131,16 +131,6 @@ __libc_fork (void) __malloc_fork_lock_parent (); } -#ifndef NDEBUG - pid_t ppid = THREAD_GETMEM (THREAD_SELF, tid); -#endif - - /* We need to prevent the getpid() code to update the PID field so - that, if a signal arrives in the child very early and the signal - handler uses getpid(), the value returned is correct. */ - pid_t parentpid = THREAD_GETMEM (THREAD_SELF, pid); - THREAD_SETMEM (THREAD_SELF, pid, -parentpid); - #ifdef ARCH_FORK pid = ARCH_FORK (); #else @@ -153,15 +143,10 @@ __libc_fork (void) { struct pthread *self = THREAD_SELF; - assert (THREAD_GETMEM (self, tid) != ppid); - /* See __pthread_once. */ if (__fork_generation_pointer != NULL) *__fork_generation_pointer += __PTHREAD_ONCE_FORK_GEN_INCR; - /* Adjust the PID field for the new process. */ - THREAD_SETMEM (self, pid, THREAD_GETMEM (self, tid)); - #if HP_TIMING_AVAIL /* The CPU clock of the thread and process have to be set to zero. */ hp_timing_t now; @@ -231,11 +216,6 @@ __libc_fork (void) } else { - assert (THREAD_GETMEM (THREAD_SELF, tid) == ppid); - - /* Restore the PID value. */ - THREAD_SETMEM (THREAD_SELF, pid, parentpid); - /* Release acquired locks in the multi-threaded case. */ if (multiple_threads) { diff --git a/sysdeps/posix/wait3.c b/sysdeps/posix/wait3.c index cf43d973a7..73722d2be6 100644 --- a/sysdeps/posix/wait3.c +++ b/sysdeps/posix/wait3.c @@ -33,7 +33,7 @@ __wait3 (int *stat_loc, int options, struct rusage *usage) __set_errno (ENOSYS); return (pid_t) -1; } - return __waitpid (WAIT_ANY, stat_loc.__iptr, options); + return __waitpid (WAIT_ANY, stat_loc, options); } weak_alias (__wait3, wait3) diff --git a/sysdeps/powerpc/fpu/libm-test-ulps b/sysdeps/powerpc/fpu/libm-test-ulps index 7f37c813d0..36b700c520 100644 --- a/sysdeps/powerpc/fpu/libm-test-ulps +++ b/sysdeps/powerpc/fpu/libm-test-ulps @@ -36,8 +36,8 @@ double: 2 float: 2 idouble: 2 ifloat: 2 -ildouble: 1 -ldouble: 1 +ildouble: 2 +ldouble: 2 Function: "acosh_downward": double: 1 @@ -52,8 +52,8 @@ double: 2 float: 2 idouble: 2 ifloat: 2 -ildouble: 3 -ldouble: 3 +ildouble: 4 +ldouble: 4 Function: "acosh_upward": double: 2 @@ -122,8 +122,8 @@ double: 3 float: 3 idouble: 3 ifloat: 3 -ildouble: 4 -ldouble: 4 +ildouble: 7 +ldouble: 7 Function: "atan": double: 1 @@ -216,8 +216,8 @@ double: 3 float: 3 idouble: 3 ifloat: 3 -ildouble: 3 -ldouble: 3 +ildouble: 4 +ldouble: 4 Function: "cabs": double: 1 @@ -272,8 +272,8 @@ double: 5 float: 3 idouble: 5 ifloat: 3 -ildouble: 5 -ldouble: 5 +ildouble: 8 +ldouble: 8 Function: Real part of "cacos_towardzero": double: 2 @@ -288,8 +288,8 @@ double: 5 float: 3 idouble: 5 ifloat: 3 -ildouble: 5 -ldouble: 5 +ildouble: 8 +ldouble: 8 Function: Real part of "cacos_upward": double: 2 @@ -328,8 +328,8 @@ double: 5 float: 3 idouble: 5 ifloat: 3 -ildouble: 5 -ldouble: 5 +ildouble: 8 +ldouble: 8 Function: Imaginary part of "cacosh_downward": double: 2 @@ -344,8 +344,8 @@ double: 5 float: 3 idouble: 5 ifloat: 3 -ildouble: 5 -ldouble: 5 +ildouble: 8 +ldouble: 8 Function: Imaginary part of "cacosh_towardzero": double: 2 @@ -432,8 +432,8 @@ double: 5 float: 3 idouble: 5 ifloat: 3 -ildouble: 5 -ldouble: 5 +ildouble: 8 +ldouble: 8 Function: Real part of "casin_towardzero": double: 3 @@ -448,8 +448,8 @@ double: 5 float: 3 idouble: 5 ifloat: 3 -ildouble: 5 -ldouble: 5 +ildouble: 8 +ldouble: 8 Function: Real part of "casin_upward": double: 2 @@ -488,8 +488,8 @@ double: 5 float: 3 idouble: 5 ifloat: 3 -ildouble: 5 -ldouble: 5 +ildouble: 8 +ldouble: 8 Function: Imaginary part of "casinh_downward": double: 3 @@ -504,8 +504,8 @@ double: 5 float: 3 idouble: 5 ifloat: 3 -ildouble: 5 -ldouble: 5 +ildouble: 8 +ldouble: 8 Function: Imaginary part of "casinh_towardzero": double: 3 @@ -696,8 +696,8 @@ double: 1 float: 1 idouble: 1 ifloat: 1 -ildouble: 1 -ldouble: 1 +ildouble: 2 +ldouble: 2 Function: Real part of "ccos_downward": double: 1 @@ -1132,8 +1132,8 @@ double: 1 float: 1 idouble: 1 ifloat: 1 -ildouble: 1 -ldouble: 1 +ildouble: 2 +ldouble: 2 Function: Imaginary part of "csin": ildouble: 1 @@ -1198,8 +1198,8 @@ double: 1 float: 1 idouble: 1 ifloat: 1 -ildouble: 1 -ldouble: 1 +ildouble: 2 +ldouble: 2 Function: Real part of "csinh_downward": double: 2 @@ -1318,8 +1318,8 @@ double: 1 float: 1 idouble: 1 ifloat: 1 -ildouble: 2 -ldouble: 2 +ildouble: 3 +ldouble: 3 Function: Imaginary part of "ctan": double: 2 @@ -1390,8 +1390,8 @@ double: 2 float: 1 idouble: 2 ifloat: 1 -ildouble: 2 -ldouble: 2 +ildouble: 3 +ldouble: 3 Function: Real part of "ctanh_downward": double: 4 @@ -1478,8 +1478,8 @@ double: 2 float: 2 idouble: 2 ifloat: 2 -ildouble: 2 -ldouble: 2 +ildouble: 3 +ldouble: 3 Function: "erfc_downward": double: 3 @@ -1564,8 +1564,8 @@ double: 1 float: 1 idouble: 1 ifloat: 1 -ildouble: 1 -ldouble: 1 +ildouble: 2 +ldouble: 2 Function: "exp2_upward": double: 1 @@ -1588,8 +1588,8 @@ ildouble: 2 ldouble: 2 Function: "exp_upward": -float: 1 double: 1 +float: 1 idouble: 1 ifloat: 1 ildouble: 1 @@ -1624,8 +1624,8 @@ double: 1 float: 1 idouble: 1 ifloat: 1 -ildouble: 4 -ldouble: 4 +ildouble: 6 +ldouble: 6 Function: "fma": ildouble: 1 @@ -1688,8 +1688,8 @@ double: 4 float: 5 idouble: 4 ifloat: 5 -ildouble: 10 -ldouble: 10 +ildouble: 11 +ldouble: 11 Function: "hypot": double: 1 @@ -1752,8 +1752,8 @@ double: 1 float: 2 idouble: 1 ifloat: 2 -ildouble: 1 -ldouble: 1 +ildouble: 2 +ldouble: 2 Function: "j1_downward": double: 3 @@ -1840,8 +1840,8 @@ double: 4 float: 5 idouble: 4 ifloat: 5 -ildouble: 10 -ldouble: 10 +ildouble: 11 +ldouble: 11 Function: "log": float: 1 @@ -1910,8 +1910,8 @@ double: 2 float: 2 idouble: 2 ifloat: 2 -ildouble: 2 -ldouble: 2 +ildouble: 3 +ldouble: 3 Function: "log2": double: 1 @@ -2184,16 +2184,16 @@ double: 3 float: 3 idouble: 3 ifloat: 3 -ildouble: 3 -ldouble: 3 +ildouble: 4 +ldouble: 4 Function: "tanh_towardzero": double: 2 float: 2 idouble: 2 ifloat: 2 -ildouble: 3 -ldouble: 3 +ildouble: 4 +ldouble: 4 Function: "tanh_upward": double: 3 diff --git a/sysdeps/powerpc/ifunc-sel.h b/sysdeps/powerpc/ifunc-sel.h index 526d8ed88b..ac589bd3c0 100644 --- a/sysdeps/powerpc/ifunc-sel.h +++ b/sysdeps/powerpc/ifunc-sel.h @@ -17,15 +17,17 @@ ifunc_sel (int (*f1) (void), int (*f2) (void), int (*f3) (void)) "addis %0,11,%2-1b@ha\n\t" "addi %0,%0,%2-1b@l\n\t" "cmpwi 12,1\n\t" - "beqlr\n\t" + "beq 2f\n\t" "addis %0,11,%3-1b@ha\n\t" "addi %0,%0,%3-1b@l\n\t" "cmpwi 12,-1\n\t" - "beqlr\n\t" + "beq 2f\n\t" "addis %0,11,%4-1b@ha\n\t" - "addi %0,%0,%4-1b@l" + "addi %0,%0,%4-1b@l\n\t" + "2:" : "=r" (ret) - : "X" (&global), "X" (f1), "X" (f2), "X" (f3)); + : "i" (&global), "i" (f1), "i" (f2), "i" (f3) + : "11", "12", "cr0"); return ret; } @@ -40,7 +42,8 @@ ifunc_one (int (*f1) (void)) "addis %0,%0,%1-1b@ha\n\t" "addi %0,%0,%1-1b@l" : "=r" (ret) - : "X" (f1)); + : "i" (f1) + : "12"); return ret; } #endif diff --git a/sysdeps/powerpc/nptl/tcb-offsets.sym b/sysdeps/powerpc/nptl/tcb-offsets.sym index f580e69555..7c9fd33562 100644 --- a/sysdeps/powerpc/nptl/tcb-offsets.sym +++ b/sysdeps/powerpc/nptl/tcb-offsets.sym @@ -13,7 +13,6 @@ #if TLS_MULTIPLE_THREADS_IN_TCB MULTIPLE_THREADS_OFFSET thread_offsetof (header.multiple_threads) #endif -PID thread_offsetof (pid) TID thread_offsetof (tid) POINTER_GUARD (offsetof (tcbhead_t, pointer_guard) - TLS_TCB_OFFSET - sizeof (tcbhead_t)) TAR_SAVE (offsetof (tcbhead_t, tar_save) - TLS_TCB_OFFSET - sizeof (tcbhead_t)) diff --git a/sysdeps/powerpc/powerpc32/power6/memset.S b/sysdeps/powerpc/powerpc32/power6/memset.S index b2a222edd2..d5dbe83af2 100644 --- a/sysdeps/powerpc/powerpc32/power6/memset.S +++ b/sysdeps/powerpc/powerpc32/power6/memset.S @@ -394,7 +394,7 @@ L(cacheAlignedx): /* A simple loop for the longer (>640 bytes) lengths. This form limits the branch miss-predicted to exactly 1 at loop exit.*/ L(cacheAligned512): - cmpli cr1,rLEN,128 + cmplwi cr1,rLEN,128 blt cr1,L(cacheAligned1) dcbz 0,rMEMP addi rLEN,rLEN,-128 diff --git a/sysdeps/powerpc/powerpc32/power9/multiarch/Implies b/sysdeps/powerpc/powerpc32/power9/multiarch/Implies index 4393b56872..1a46ef0035 100644 --- a/sysdeps/powerpc/powerpc32/power9/multiarch/Implies +++ b/sysdeps/powerpc/powerpc32/power9/multiarch/Implies @@ -1 +1 @@ -powerpc/powerpc32/power8/fpu/multiarch +powerpc/powerpc32/power8/multiarch diff --git a/sysdeps/powerpc/powerpc64/power6/memset.S b/sysdeps/powerpc/powerpc64/power6/memset.S index c2d1c4e600..d445b1e1ef 100644 --- a/sysdeps/powerpc/powerpc64/power6/memset.S +++ b/sysdeps/powerpc/powerpc64/power6/memset.S @@ -251,7 +251,7 @@ L(cacheAlignedx): /* A simple loop for the longer (>640 bytes) lengths. This form limits the branch miss-predicted to exactly 1 at loop exit.*/ L(cacheAligned512): - cmpli cr1,rLEN,128 + cmpldi cr1,rLEN,128 blt cr1,L(cacheAligned1) dcbz 0,rMEMP addi rLEN,rLEN,-128 diff --git a/sysdeps/powerpc/powerpc64/power9/fpu/Implies b/sysdeps/powerpc/powerpc64/power9/fpu/Implies index fad2505ab9..ae0dbaf857 100644 --- a/sysdeps/powerpc/powerpc64/power9/fpu/Implies +++ b/sysdeps/powerpc/powerpc64/power9/fpu/Implies @@ -1,2 +1 @@ powerpc/powerpc64/power8/fpu -powerpc/powerpc64/power8 diff --git a/sysdeps/s390/nptl/Makefile b/sysdeps/s390/nptl/Makefile index 5734b983b0..3a391c8217 100644 --- a/sysdeps/s390/nptl/Makefile +++ b/sysdeps/s390/nptl/Makefile @@ -21,4 +21,5 @@ endif ifeq ($(subdir),nptl) libpthread-routines += ptw-sysdep +libpthread-shared-only-routines += ptw-sysdep endif diff --git a/sysdeps/s390/nptl/tcb-offsets.sym b/sysdeps/s390/nptl/tcb-offsets.sym index 9cfae211e0..9c1c01f353 100644 --- a/sysdeps/s390/nptl/tcb-offsets.sym +++ b/sysdeps/s390/nptl/tcb-offsets.sym @@ -3,5 +3,4 @@ MULTIPLE_THREADS_OFFSET offsetof (tcbhead_t, multiple_threads) STACK_GUARD offsetof (tcbhead_t, stack_guard) -PID offsetof (struct pthread, pid) TID offsetof (struct pthread, tid) diff --git a/sysdeps/sh/nptl/tcb-offsets.sym b/sysdeps/sh/nptl/tcb-offsets.sym index ac63b5b93b..4963e1506f 100644 --- a/sysdeps/sh/nptl/tcb-offsets.sym +++ b/sysdeps/sh/nptl/tcb-offsets.sym @@ -4,7 +4,6 @@ RESULT offsetof (struct pthread, result) TID offsetof (struct pthread, tid) -PID offsetof (struct pthread, pid) CANCELHANDLING offsetof (struct pthread, cancelhandling) CLEANUP_JMP_BUF offsetof (struct pthread, cleanup_jmp_buf) MULTIPLE_THREADS_OFFSET offsetof (struct pthread, header.multiple_threads) diff --git a/sysdeps/sparc/nptl/tcb-offsets.sym b/sysdeps/sparc/nptl/tcb-offsets.sym index 923af8a5b7..f75d02065e 100644 --- a/sysdeps/sparc/nptl/tcb-offsets.sym +++ b/sysdeps/sparc/nptl/tcb-offsets.sym @@ -3,5 +3,4 @@ MULTIPLE_THREADS_OFFSET offsetof (tcbhead_t, multiple_threads) POINTER_GUARD offsetof (tcbhead_t, pointer_guard) -PID offsetof (struct pthread, pid) TID offsetof (struct pthread, tid) diff --git a/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/Makefile b/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/Makefile index ebbe28b07f..13d3c6db51 100644 --- a/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/Makefile +++ b/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/Makefile @@ -4,8 +4,8 @@ libm-sysdep_routines += m_copysignf-vis3 m_copysign-vis3 s_fabs-vis3 \ s_fabsf-vis3 s_llrintf-vis3 s_llrint-vis3 \ s_rintf-vis3 s_rint-vis3 w_sqrt-vis3 w_sqrtf-vis3 \ s_fminf-vis3 s_fmin-vis3 s_fmaxf-vis3 s_fmax-vis3 \ - s_fmaf-vis3 s_fma-vis3 s_fdimf-vis3 s_fdim-vis3 \ - s_nearbyint-vis3 s_nearbyintf-vis3 + s_fmaf-vis3 s_fma-vis3 s_nearbyint-vis3 \ + s_nearbyintf-vis3 sysdep_routines += s_copysignf-vis3 s_copysign-vis3 endif endif diff --git a/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdim.S b/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdim.S deleted file mode 100644 index 4b13408244..0000000000 --- a/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdim.S +++ /dev/null @@ -1,19 +0,0 @@ -#include -#include - -SPARC_ASM_VIS3_IFUNC(fdim) - -weak_alias (__fdim, fdim) - -#if LONG_DOUBLE_COMPAT(libm, GLIBC_2_1) -compat_symbol (libm, __fdim, fdiml, GLIBC_2_1); -#endif - -# undef weak_alias -# define weak_alias(a, b) -# undef compat_symbol -# define compat_symbol(a, b, c, d) - -#define __fdim __fdim_generic - -#include "../s_fdim.S" diff --git a/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdimf.S b/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdimf.S deleted file mode 100644 index 30381d6a59..0000000000 --- a/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdimf.S +++ /dev/null @@ -1,12 +0,0 @@ -#include - -SPARC_ASM_VIS3_IFUNC(fdimf) - -weak_alias (__fdimf, fdimf) - -# undef weak_alias -# define weak_alias(a, b) - -#define __fdimf __fdimf_generic - -#include "../s_fdimf.S" diff --git a/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_nearbyint-vis3.S b/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_nearbyint-vis3.S index d9ff0cc288..ff81b0da83 100644 --- a/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_nearbyint-vis3.S +++ b/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_nearbyint-vis3.S @@ -36,15 +36,15 @@ #define SIGN_BIT %f12 /* -0.0 */ ENTRY (__nearbyint_vis3) + sllx %o0, 32, %o0 + or %o0, %o1, %o0 + movxtod %o0, %f0 fcmpd %fcc3, %f0, %f0 /* Check for sNaN */ st %fsr, [%sp + 88] sethi %hi(TWO_FIFTYTWO), %o2 sethi %hi(0xf8003e0), %o5 ld [%sp + 88], %o4 - sllx %o0, 32, %o0 or %o5, %lo(0xf8003e0), %o5 - or %o0, %o1, %o0 - movxtod %o0, %f0 andn %o4, %o5, %o4 fzero ZERO st %o4, [%sp + 80] diff --git a/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_nearbyintf-vis3.S b/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_nearbyintf-vis3.S index 5cd1eb02db..833a0dfc24 100644 --- a/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_nearbyintf-vis3.S +++ b/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_nearbyintf-vis3.S @@ -35,9 +35,9 @@ #define SIGN_BIT %f12 /* -0.0 */ ENTRY (__nearbyintf_vis3) + movwtos %o0, %f1 fcmps %fcc3, %f1, %f1 /* Check for sNaN */ st %fsr, [%sp + 88] - movwtos %o0, %f1 sethi %hi(TWO_TWENTYTHREE), %o2 sethi %hi(0xf8003e0), %o5 ld [%sp + 88], %o4 diff --git a/sysdeps/sparc/sparc32/sparcv9/fpu/s_nearbyint.S b/sysdeps/sparc/sparc32/sparcv9/fpu/s_nearbyint.S index 84a10971a4..198440a5bc 100644 --- a/sysdeps/sparc/sparc32/sparcv9/fpu/s_nearbyint.S +++ b/sysdeps/sparc/sparc32/sparcv9/fpu/s_nearbyint.S @@ -36,21 +36,21 @@ #define SIGN_BIT %f12 /* -0.0 */ ENTRY (__nearbyint) + sllx %o0, 32, %o0 + or %o0, %o1, %o0 + stx %o0, [%sp + 72] + ldd [%sp + 72], %f0 fcmpd %fcc3, %f0, %f0 /* Check for sNaN */ st %fsr, [%sp + 88] sethi %hi(TWO_FIFTYTWO), %o2 sethi %hi(0xf8003e0), %o5 ld [%sp + 88], %o4 - sllx %o0, 32, %o0 or %o5, %lo(0xf8003e0), %o5 - or %o0, %o1, %o0 andn %o4, %o5, %o4 fzero ZERO st %o4, [%sp + 80] - stx %o0, [%sp + 72] sllx %o2, 32, %o2 fnegd ZERO, SIGN_BIT - ldd [%sp + 72], %f0 ld [%sp + 80], %fsr stx %o2, [%sp + 72] fabsd %f0, %f14 diff --git a/sysdeps/sparc/sparc32/sparcv9/fpu/s_nearbyintf.S b/sysdeps/sparc/sparc32/sparcv9/fpu/s_nearbyintf.S index d5cf5ce815..9be41f6c22 100644 --- a/sysdeps/sparc/sparc32/sparcv9/fpu/s_nearbyintf.S +++ b/sysdeps/sparc/sparc32/sparcv9/fpu/s_nearbyintf.S @@ -35,9 +35,10 @@ #define SIGN_BIT %f12 /* -0.0 */ ENTRY (__nearbyintf) + st %o0, [%sp + 68] + ld [%sp + 68], %f1 fcmps %fcc3, %f1, %f1 /* Check for sNaN */ st %fsr, [%sp + 88] - st %o0, [%sp + 68] sethi %hi(TWO_TWENTYTHREE), %o2 sethi %hi(0xf8003e0), %o5 ld [%sp + 88], %o4 @@ -46,7 +47,6 @@ ENTRY (__nearbyintf) fnegs ZERO, SIGN_BIT andn %o4, %o5, %o4 st %o4, [%sp + 80] - ld [%sp + 68], %f1 ld [%sp + 80], %fsr st %o2, [%sp + 68] fabss %f1, %f14 diff --git a/sysdeps/tile/nptl/tcb-offsets.sym b/sysdeps/tile/nptl/tcb-offsets.sym index 6740bc976f..0147ffafb7 100644 --- a/sysdeps/tile/nptl/tcb-offsets.sym +++ b/sysdeps/tile/nptl/tcb-offsets.sym @@ -9,7 +9,6 @@ #define thread_offsetof(mem) (long)(offsetof(struct pthread, mem) - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE) MULTIPLE_THREADS_OFFSET thread_offsetof (header.multiple_threads) -PID_OFFSET thread_offsetof (pid) TID_OFFSET thread_offsetof (tid) POINTER_GUARD (offsetof (tcbhead_t, pointer_guard) - TLS_TCB_OFFSET - sizeof (tcbhead_t)) FEEDBACK_DATA_OFFSET (offsetof (tcbhead_t, feedback_data) - TLS_TCB_OFFSET - sizeof (tcbhead_t)) diff --git a/sysdeps/unix/alpha/Makefile b/sysdeps/unix/alpha/Makefile index 441aa02a83..0660847f15 100644 --- a/sysdeps/unix/alpha/Makefile +++ b/sysdeps/unix/alpha/Makefile @@ -1,3 +1,4 @@ ifeq ($(subdir),rt) librt-sysdep_routines += rt-sysdep +librt-shared-only-routines += rt-sysdep endif diff --git a/sysdeps/unix/sysdep.h b/sysdeps/unix/sysdep.h index 94a2ce0e37..38c2432002 100644 --- a/sysdeps/unix/sysdep.h +++ b/sysdeps/unix/sysdep.h @@ -24,42 +24,79 @@ #define SYSCALL__(name, args) PSEUDO (__##name, name, args) #define SYSCALL(name, args) PSEUDO (name, name, args) -#define __SYSCALL0(name) \ +#define __SYSCALL_CONCAT_X(a,b) a##b +#define __SYSCALL_CONCAT(a,b) __SYSCALL_CONCAT_X (a, b) + + +#define __INTERNAL_SYSCALL0(name, err) \ + INTERNAL_SYSCALL (name, err, 0) +#define __INTERNAL_SYSCALL1(name, err, a1) \ + INTERNAL_SYSCALL (name, err, 1, a1) +#define __INTERNAL_SYSCALL2(name, err, a1, a2) \ + INTERNAL_SYSCALL (name, err, 2, a1, a2) +#define __INTERNAL_SYSCALL3(name, err, a1, a2, a3) \ + INTERNAL_SYSCALL (name, err, 3, a1, a2, a3) +#define __INTERNAL_SYSCALL4(name, err, a1, a2, a3, a4) \ + INTERNAL_SYSCALL (name, err, 4, a1, a2, a3, a4) +#define __INTERNAL_SYSCALL5(name, err, a1, a2, a3, a4, a5) \ + INTERNAL_SYSCALL (name, err, 5, a1, a2, a3, a4, a5) +#define __INTERNAL_SYSCALL6(name, err, a1, a2, a3, a4, a5, a6) \ + INTERNAL_SYSCALL (name, err, 6, a1, a2, a3, a4, a5, a6) +#define __INTERNAL_SYSCALL7(name, err, a1, a2, a3, a4, a5, a6, a7) \ + INTERNAL_SYSCALL (name, err, 7, a1, a2, a3, a4, a5, a6, a7) + +#define __INTERNAL_SYSCALL_NARGS_X(a,b,c,d,e,f,g,h,n,o,...) o +#define __INTERNAL_SYSCALL_NARGS(...) \ + __INTERNAL_SYSCALL_NARGS_X (__VA_ARGS__,7,6,5,4,3,2,1,0,) +#define __INTERNAL_SYSCALL_DISP(b,...) \ + __SYSCALL_CONCAT (b,__INTERNAL_SYSCALL_NARGS(__VA_ARGS__))(__VA_ARGS__) + +/* Issue a syscall defined by syscall number plus any other argument required. + It is similar to INTERNAL_SYSCALL macro, but without the need to pass the + expected argument number as second parameter. */ +#define INTERNAL_SYSCALL_CALL(...) \ + __INTERNAL_SYSCALL_DISP (__INTERNAL_SYSCALL, __VA_ARGS__) + +#define __INLINE_SYSCALL0(name) \ INLINE_SYSCALL (name, 0) -#define __SYSCALL1(name, a1) \ +#define __INLINE_SYSCALL1(name, a1) \ INLINE_SYSCALL (name, 1, a1) -#define __SYSCALL2(name, a1, a2) \ +#define __INLINE_SYSCALL2(name, a1, a2) \ INLINE_SYSCALL (name, 2, a1, a2) -#define __SYSCALL3(name, a1, a2, a3) \ +#define __INLINE_SYSCALL3(name, a1, a2, a3) \ INLINE_SYSCALL (name, 3, a1, a2, a3) -#define __SYSCALL4(name, a1, a2, a3, a4) \ +#define __INLINE_SYSCALL4(name, a1, a2, a3, a4) \ INLINE_SYSCALL (name, 4, a1, a2, a3, a4) -#define __SYSCALL5(name, a1, a2, a3, a4, a5) \ +#define __INLINE_SYSCALL5(name, a1, a2, a3, a4, a5) \ INLINE_SYSCALL (name, 5, a1, a2, a3, a4, a5) -#define __SYSCALL6(name, a1, a2, a3, a4, a5, a6) \ +#define __INLINE_SYSCALL6(name, a1, a2, a3, a4, a5, a6) \ INLINE_SYSCALL (name, 6, a1, a2, a3, a4, a5, a6) -#define __SYSCALL7(name, a1, a2, a3, a4, a5, a6, a7) \ +#define __INLINE_SYSCALL7(name, a1, a2, a3, a4, a5, a6, a7) \ INLINE_SYSCALL (name, 7, a1, a2, a3, a4, a5, a6, a7) -#define __SYSCALL_NARGS_X(a,b,c,d,e,f,g,h,n,...) n -#define __SYSCALL_NARGS(...) \ - __SYSCALL_NARGS_X (__VA_ARGS__,7,6,5,4,3,2,1,0,) -#define __SYSCALL_CONCAT_X(a,b) a##b -#define __SYSCALL_CONCAT(a,b) __SYSCALL_CONCAT_X (a, b) -#define __SYSCALL_DISP(b,...) \ - __SYSCALL_CONCAT (b,__SYSCALL_NARGS(__VA_ARGS__))(__VA_ARGS__) +#define __INLINE_SYSCALL_NARGS_X(a,b,c,d,e,f,g,h,n,...) n +#define __INLINE_SYSCALL_NARGS(...) \ + __INLINE_SYSCALL_NARGS_X (__VA_ARGS__,7,6,5,4,3,2,1,0,) +#define __INLINE_SYSCALL_DISP(b,...) \ + __SYSCALL_CONCAT (b,__INLINE_SYSCALL_NARGS(__VA_ARGS__))(__VA_ARGS__) -#define __SYSCALL_CALL(...) __SYSCALL_DISP (__SYSCALL, __VA_ARGS__) +/* Issue a syscall defined by syscall number plus any other argument + required. Any error will be handled using arch defined macros and errno + will be set accordingly. + It is similar to INLINE_SYSCALL macro, but without the need to pass the + expected argument number as second parameter. */ +#define INLINE_SYSCALL_CALL(...) \ + __INLINE_SYSCALL_DISP (__INLINE_SYSCALL, __VA_ARGS__) #define SYSCALL_CANCEL(...) \ ({ \ long int sc_ret; \ if (SINGLE_THREAD_P) \ - sc_ret = __SYSCALL_CALL (__VA_ARGS__); \ + sc_ret = INLINE_SYSCALL_CALL (__VA_ARGS__); \ else \ { \ int sc_cancel_oldtype = LIBC_CANCEL_ASYNC (); \ - sc_ret = __SYSCALL_CALL (__VA_ARGS__); \ + sc_ret = INLINE_SYSCALL_CALL (__VA_ARGS__); \ LIBC_CANCEL_RESET (sc_cancel_oldtype); \ } \ sc_ret; \ diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile index 35e1ed48d2..32beaa67d0 100644 --- a/sysdeps/unix/sysv/linux/Makefile +++ b/sysdeps/unix/sysv/linux/Makefile @@ -140,7 +140,7 @@ endif ifeq ($(subdir),posix) sysdep_headers += bits/initspin.h -sysdep_routines += sched_getcpu +sysdep_routines += sched_getcpu oldglob tests += tst-affinity tst-affinity-pid diff --git a/sysdeps/unix/sysv/linux/aarch64/clone.S b/sysdeps/unix/sysv/linux/aarch64/clone.S index 76baa7a698..96482e53c0 100644 --- a/sysdeps/unix/sysv/linux/aarch64/clone.S +++ b/sysdeps/unix/sysv/linux/aarch64/clone.S @@ -72,16 +72,6 @@ thread_start: cfi_undefined (x30) mov x29, 0 - tbnz x11, #CLONE_VM_BIT, 1f - - mov x8, #SYS_ify(getpid) - svc 0x0 - mrs x1, tpidr_el0 - sub x1, x1, #PTHREAD_SIZEOF - str w0, [x1, #PTHREAD_PID_OFFSET] - str w0, [x1, #PTHREAD_TID_OFFSET] -1: - /* Pick the function arg and execute. */ mov x0, x12 blr x10 diff --git a/sysdeps/unix/sysv/linux/aarch64/vfork.S b/sysdeps/unix/sysv/linux/aarch64/vfork.S index 577895eeb2..aeed0b29ce 100644 --- a/sysdeps/unix/sysv/linux/aarch64/vfork.S +++ b/sysdeps/unix/sysv/linux/aarch64/vfork.S @@ -27,27 +27,10 @@ ENTRY (__vfork) - /* Save the TCB-cached PID away in w3, and then negate the TCB - field. But if it's zero, set it to 0x80000000 instead. See - raise.c for the logic that relies on this value. */ - mrs x2, tpidr_el0 - sub x2, x2, #PTHREAD_SIZEOF - ldr w3, [x2, #PTHREAD_PID_OFFSET] - mov w1, #0x80000000 - negs w0, w3 - csel w0, w1, w0, eq - str w0, [x2, #PTHREAD_PID_OFFSET] - mov x0, #0x4111 /* CLONE_VM | CLONE_VFORK | SIGCHLD */ mov x1, sp DO_CALL (clone, 2) - /* Restore the original value of the TCB cache of the PID, if we're - the parent. But in the child (syscall return value equals zero), - leave things as they are. */ - cbz x0, 1f - str w3, [x2, #PTHREAD_PID_OFFSET] -1: cmn x0, #4095 b.cs .Lsyscall_error RET diff --git a/sysdeps/unix/sysv/linux/alpha/Makefile b/sysdeps/unix/sysv/linux/alpha/Makefile index c089545e9b..3b523b70cf 100644 --- a/sysdeps/unix/sysv/linux/alpha/Makefile +++ b/sysdeps/unix/sysv/linux/alpha/Makefile @@ -40,4 +40,5 @@ endif # math ifeq ($(subdir),nptl) # pull in __syscall_error routine, __sigprocmask, __syscall_rt_sigaction libpthread-routines += ptw-sysdep ptw-sigprocmask ptw-rt_sigaction +libpthread-shared-only-routines += ptw-sysdep ptw-sigprocmask ptw-rt_sigaction endif diff --git a/sysdeps/unix/sysv/linux/alpha/clone.S b/sysdeps/unix/sysv/linux/alpha/clone.S index 6a3154f9a7..2757bf20c3 100644 --- a/sysdeps/unix/sysv/linux/alpha/clone.S +++ b/sysdeps/unix/sysv/linux/alpha/clone.S @@ -91,13 +91,6 @@ thread_start: cfi_def_cfa_register(fp) cfi_undefined(ra) - /* Check and see if we need to reset the PID. */ - ldq t0, 16(sp) - lda t1, CLONE_VM - and t0, t1, t2 - beq t2, 2f -1: - /* Load up the arguments. */ ldq pv, 0(sp) ldq a0, 8(sp) @@ -120,15 +113,6 @@ thread_start: halt .align 4 -2: - rduniq - mov v0, s0 - lda v0, __NR_getxpid - callsys -3: - stl v0, PID_OFFSET(s0) - stl v0, TID_OFFSET(s0) - br 1b cfi_endproc .end thread_start diff --git a/sysdeps/unix/sysv/linux/alpha/glob.c b/sysdeps/unix/sysv/linux/alpha/glob.c index c5dfb85468..19eb9b1c07 100644 --- a/sysdeps/unix/sysv/linux/alpha/glob.c +++ b/sysdeps/unix/sysv/linux/alpha/glob.c @@ -42,10 +42,6 @@ extern void __new_globfree (glob_t *__pglob); #undef globfree64 versioned_symbol (libc, __new_glob, glob, GLIBC_2_1); -versioned_symbol (libc, __new_globfree, globfree, GLIBC_2_1); libc_hidden_ver (__new_glob, glob) -libc_hidden_ver (__new_globfree, globfree) weak_alias (__new_glob, glob64) -weak_alias (__new_globfree, globfree64) -libc_hidden_ver (__new_globfree, globfree64) diff --git a/sysdeps/unix/sysv/linux/alpha/globfree.c b/sysdeps/unix/sysv/linux/alpha/globfree.c new file mode 100644 index 0000000000..98cf1c200b --- /dev/null +++ b/sysdeps/unix/sysv/linux/alpha/globfree.c @@ -0,0 +1,37 @@ +/* Compat globfree. Linux/alpha version. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library. If not, see + . */ + +#define globfree64 __no_globfree64_decl +#include +#include +#include + +#define globfree(pglob) \ + __new_globfree (pglob) + +extern void __new_globfree (glob_t *__pglob); + +#include + +#undef globfree64 + +versioned_symbol (libc, __new_globfree, globfree, GLIBC_2_1); +libc_hidden_ver (__new_globfree, globfree) + +weak_alias (__new_globfree, globfree64) +libc_hidden_ver (__new_globfree, globfree64) diff --git a/sysdeps/unix/sysv/linux/alpha/vfork.S b/sysdeps/unix/sysv/linux/alpha/vfork.S index 9fc199ac41..e5f7ed0661 100644 --- a/sysdeps/unix/sysv/linux/alpha/vfork.S +++ b/sysdeps/unix/sysv/linux/alpha/vfork.S @@ -25,24 +25,9 @@ ENTRY(__libc_vfork) rduniq mov v0, a1 - /* Save the TCB-cached PID away in A2, and then negate the TCB - field. But if it's zero, set it to 0x80000000 instead. See - raise.c for the logic that relies on this value. */ - ldl a2, PID_OFFSET(v0) - ldah t0, -0x8000 - negl a2, t1 - cmovne a2, t1, t0 - stl t0, PID_OFFSET(v0); - lda v0, SYS_ify(vfork) call_pal PAL_callsys - /* Restore the original value of the TCB cache of the PID, if we're - the parent. But in the child (syscall return value equals zero), - leave things as they are. */ - beq v0, 1f - stl a2, PID_OFFSET(a1) -1: /* Normal error check and return. */ bne a3, SYSCALL_ERROR_LABEL ret diff --git a/sysdeps/unix/sysv/linux/arm/clone.S b/sysdeps/unix/sysv/linux/arm/clone.S index 7ff681804b..4c6325d088 100644 --- a/sysdeps/unix/sysv/linux/arm/clone.S +++ b/sysdeps/unix/sysv/linux/arm/clone.S @@ -70,16 +70,6 @@ PSEUDO_END (__clone) 1: .fnstart .cantunwind - tst ip, #CLONE_VM - bne 2f - GET_TLS (lr) - mov r1, r0 - ldr r7, =SYS_ify(getpid) - swi 0x0 - NEGOFF_ADJ_BASE (r1, TID_OFFSET) - str r0, NEGOFF_OFF1 (r1, TID_OFFSET) - str r0, NEGOFF_OFF2 (r1, PID_OFFSET, TID_OFFSET) -2: @ pick the function arg and call address off the stack and execute ldr r0, [sp, #4] ldr ip, [sp], #8 diff --git a/sysdeps/unix/sysv/linux/arm/setcontext.S b/sysdeps/unix/sysv/linux/arm/setcontext.S index 603e508858..d1f168fece 100644 --- a/sysdeps/unix/sysv/linux/arm/setcontext.S +++ b/sysdeps/unix/sysv/linux/arm/setcontext.S @@ -86,12 +86,19 @@ weak_alias(__setcontext, setcontext) /* Called when a makecontext() context returns. Start the context in R4 or fall through to exit(). */ + /* Unwind descriptors are looked up based on PC - 2, so we have to + make sure to mark the instruction preceding the __startcontext + label as .cantunwind. */ + .fnstart + .cantunwind + nop ENTRY(__startcontext) movs r0, r4 bne PLTJMP(__setcontext) @ New context was 0 - exit b PLTJMP(HIDDEN_JUMPTARGET(exit)) + .fnend END(__startcontext) #ifdef PIC diff --git a/sysdeps/unix/sysv/linux/arm/vfork.S b/sysdeps/unix/sysv/linux/arm/vfork.S index 500f5ca4be..794372ee12 100644 --- a/sysdeps/unix/sysv/linux/arm/vfork.S +++ b/sysdeps/unix/sysv/linux/arm/vfork.S @@ -28,16 +28,6 @@ and the process ID of the new process to the old process. */ ENTRY (__vfork) - /* Save the PID value. */ - GET_TLS (r2) - NEGOFF_ADJ_BASE2 (r2, r0, PID_OFFSET) /* Save the TLS addr in r2. */ - ldr r3, NEGOFF_OFF1 (r2, PID_OFFSET) /* Load the saved PID. */ - rsbs r0, r3, #0 /* Negate it, and test for zero. */ - /* Use 0x80000000 if it was 0. See raise.c for how this is used. */ - it eq - moveq r0, #0x80000000 - str r0, NEGOFF_OFF1 (r2, PID_OFFSET) /* Store the temp PID. */ - /* The DO_CALL macro saves r7 on the stack, to enable generation of ARM unwind info. Since the stack is initially shared between parent and child of vfork, that saved value could be corrupted. @@ -57,11 +47,6 @@ ENTRY (__vfork) mov r7, ip cfi_restore (r7) - /* Restore the old PID value in the parent. */ - cmp r0, #0 /* If we are the parent... */ - it ne - strne r3, NEGOFF_OFF1 (r2, PID_OFFSET) /* restore the saved PID. */ - cmn a1, #4096 it cc RETINSTR(cc, lr) diff --git a/sysdeps/unix/sysv/linux/createthread.c b/sysdeps/unix/sysv/linux/createthread.c index 6d32cece48..ec86f50814 100644 --- a/sysdeps/unix/sysv/linux/createthread.c +++ b/sysdeps/unix/sysv/linux/createthread.c @@ -128,10 +128,10 @@ create_thread (struct pthread *pd, const struct pthread_attr *attr, /* The operation failed. We have to kill the thread. We let the normal cancellation mechanism do the work. */ + pid_t pid = __getpid (); INTERNAL_SYSCALL_DECL (err2); - (void) INTERNAL_SYSCALL (tgkill, err2, 3, - THREAD_GETMEM (THREAD_SELF, pid), - pd->tid, SIGCANCEL); + (void) INTERNAL_SYSCALL_CALL (tgkill, err2, pid, pd->tid, + SIGCANCEL); return INTERNAL_SYSCALL_ERRNO (res, err); } diff --git a/sysdeps/unix/sysv/linux/getcwd.c b/sysdeps/unix/sysv/linux/getcwd.c index 3f21ae743f..d0b2c38c17 100644 --- a/sysdeps/unix/sysv/linux/getcwd.c +++ b/sysdeps/unix/sysv/linux/getcwd.c @@ -76,7 +76,7 @@ __getcwd (char *buf, size_t size) int retval; retval = INLINE_SYSCALL (getcwd, 2, path, alloc_size); - if (retval >= 0) + if (retval > 0 && path[0] == '/') { #ifndef NO_ALLOCATION if (buf == NULL && size == 0) @@ -92,10 +92,10 @@ __getcwd (char *buf, size_t size) return buf; } - /* The system call cannot handle paths longer than a page. - Neither can the magic symlink in /proc/self. Just use the + /* The system call either cannot handle paths longer than a page + or can succeed without returning an absolute path. Just use the generic implementation right away. */ - if (errno == ENAMETOOLONG) + if (retval >= 0 || errno == ENAMETOOLONG) { #ifndef NO_ALLOCATION if (buf == NULL && size == 0) diff --git a/sysdeps/unix/sysv/linux/getpid.c b/sysdeps/unix/sysv/linux/getpid.c deleted file mode 100644 index 1124549326..0000000000 --- a/sysdeps/unix/sysv/linux/getpid.c +++ /dev/null @@ -1,64 +0,0 @@ -/* Copyright (C) 2003-2016 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 2003. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - . */ - -#include -#include -#include - - -#if IS_IN (libc) -static inline __attribute__((always_inline)) pid_t really_getpid (pid_t oldval); - -static inline __attribute__((always_inline)) pid_t -really_getpid (pid_t oldval) -{ - if (__glibc_likely (oldval == 0)) - { - pid_t selftid = THREAD_GETMEM (THREAD_SELF, tid); - if (__glibc_likely (selftid != 0)) - return selftid; - } - - INTERNAL_SYSCALL_DECL (err); - pid_t result = INTERNAL_SYSCALL (getpid, err, 0); - - /* We do not set the PID field in the TID here since we might be - called from a signal handler while the thread executes fork. */ - if (oldval == 0) - THREAD_SETMEM (THREAD_SELF, tid, result); - return result; -} -#endif - -pid_t -__getpid (void) -{ -#if !IS_IN (libc) - INTERNAL_SYSCALL_DECL (err); - pid_t result = INTERNAL_SYSCALL (getpid, err, 0); -#else - pid_t result = THREAD_GETMEM (THREAD_SELF, pid); - if (__glibc_unlikely (result <= 0)) - result = really_getpid (result); -#endif - return result; -} - -libc_hidden_def (__getpid) -weak_alias (__getpid, getpid) -libc_hidden_def (getpid) diff --git a/sysdeps/unix/sysv/linux/hppa/clone.S b/sysdeps/unix/sysv/linux/hppa/clone.S index 3d037f1430..25fcd497f7 100644 --- a/sysdeps/unix/sysv/linux/hppa/clone.S +++ b/sysdeps/unix/sysv/linux/hppa/clone.S @@ -132,18 +132,6 @@ ENTRY(__clone) ldwm -64(%sp), %r4 .LthreadStart: -# define CLONE_VM_BIT 23 /* 0x00000100 */ - /* Load original clone flags. - If CLONE_VM was passed, don't modify PID/TID. - Otherwise store the result of getpid to PID/TID. */ - ldw -56(%sp), %r26 - bb,<,n %r26, CLONE_VM_BIT, 1f - ble 0x100(%sr2, %r0) - ldi __NR_getpid, %r20 - mfctl %cr27, %r26 - stw %ret0, PID_THREAD_OFFSET(%r26) - stw %ret0, TID_THREAD_OFFSET(%r26) -1: /* Load up the arguments. */ ldw -60(%sp), %arg0 ldw -64(%sp), %r22 diff --git a/sysdeps/unix/sysv/linux/hppa/pt-vfork.S b/sysdeps/unix/sysv/linux/hppa/pt-vfork.S index df532362d2..4684048502 100644 --- a/sysdeps/unix/sysv/linux/hppa/pt-vfork.S +++ b/sysdeps/unix/sysv/linux/hppa/pt-vfork.S @@ -25,26 +25,6 @@ replaced by a call to `execve'. Return -1 for errors, 0 to the new process, and the process ID of the new process to the old process. */ -/* Load the thread register. - Load the saved PID value. - Negate the value. - Store the temporary PID. */ -#define SAVE_PID \ - mfctl %cr27, %r26 ASM_LINE_SEP \ - ldw PID_THREAD_OFFSET(%r26),%r1 ASM_LINE_SEP \ - sub %r0,%r1,%r1 ASM_LINE_SEP \ - stw %r1,PID_THREAD_OFFSET(%r26) ASM_LINE_SEP -/* If we are the parent... - Get the thread pointer. - Load the saved PID. - Negate the value (got back original) - Restore the PID. */ -#define RESTORE_PID \ - cmpb,=,n %r0,%ret0,.Lthread_start ASM_LINE_SEP \ - mfctl %cr27, %r26 ASM_LINE_SEP \ - ldw PID_THREAD_OFFSET(%r26),%r1 ASM_LINE_SEP \ - sub %r0,%r1,%r1 ASM_LINE_SEP \ - stw %r1,PID_THREAD_OFFSET(%r26) ASM_LINE_SEP \ .Lthread_start: ASM_LINE_SEP /* r26, r25, r24, r23 are free since vfork has no arguments */ @@ -58,16 +38,10 @@ ENTRY(__vfork) copy %r19, %r25 /* parent */ #endif - /* Save the process PID */ - SAVE_PID - /* Syscall saves and restores all register states */ ble 0x100(%sr2,%r0) ldi __NR_vfork,%r20 - /* Conditionally restore the PID */ - RESTORE_PID - /* Check for error */ ldi -4096,%r1 comclr,>>= %r1,%ret0,%r0 /* Note: unsigned compare. */ diff --git a/sysdeps/unix/sysv/linux/i386/Makefile b/sysdeps/unix/sysv/linux/i386/Makefile index 71ba61e9d7..6073a9fe04 100644 --- a/sysdeps/unix/sysv/linux/i386/Makefile +++ b/sysdeps/unix/sysv/linux/i386/Makefile @@ -31,6 +31,7 @@ endif # libpthread uses six-argument inline syscalls. ifeq ($(subdir),nptl) libpthread-sysdep_routines += libc-do-syscall +libpthread-shared-only-routines += libc-do-syscall endif ifeq ($(subdir),resource) @@ -48,9 +49,11 @@ endif ifeq ($(subdir),nptl) # pull in __syscall_error routine libpthread-routines += sysdep +libpthread-shared-only-routines += sysdep endif ifeq ($(subdir),rt) # pull in __syscall_error routine librt-routines += sysdep +librt-shared-only-routines += sysdep endif diff --git a/sysdeps/unix/sysv/linux/i386/clone.S b/sysdeps/unix/sysv/linux/i386/clone.S index 25f2a9c340..feae504ce6 100644 --- a/sysdeps/unix/sysv/linux/i386/clone.S +++ b/sysdeps/unix/sysv/linux/i386/clone.S @@ -107,9 +107,6 @@ L(thread_start): cfi_undefined (eip); /* Note: %esi is zero. */ movl %esi,%ebp /* terminate the stack frame */ - testl $CLONE_VM, %edi - je L(newpid) -L(haspid): call *%ebx #ifdef PIC call L(here) @@ -121,18 +118,6 @@ L(here): movl $SYS_ify(exit), %eax ENTER_KERNEL - .subsection 2 -L(newpid): - movl $SYS_ify(getpid), %eax - ENTER_KERNEL -L(nomoregetpid): - movl %eax, %gs:PID - movl %eax, %gs:TID - jmp L(haspid) - .previous - cfi_endproc; - - cfi_startproc PSEUDO_END (__clone) libc_hidden_def (__clone) diff --git a/sysdeps/unix/sysv/linux/i386/glob64.c b/sysdeps/unix/sysv/linux/i386/glob64.c index 802c957d6c..c2cc85741f 100644 --- a/sysdeps/unix/sysv/linux/i386/glob64.c +++ b/sysdeps/unix/sysv/linux/i386/glob64.c @@ -19,6 +19,7 @@ #include #include #include +#include #define dirent dirent64 #define __readdir(dirp) __readdir64 (dirp) @@ -33,44 +34,9 @@ #undef __stat #define __stat(file, buf) __xstat64 (_STAT_VER, file, buf) -#define NO_GLOB_PATTERN_P 1 - #define COMPILE_GLOB64 1 #include -#include "shlib-compat.h" - -libc_hidden_def (globfree64) - versioned_symbol (libc, __glob64, glob64, GLIBC_2_2); libc_hidden_ver (__glob64, glob64) - -#if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2) - -#include - -int __old_glob64 (const char *__pattern, int __flags, - int (*__errfunc) (const char *, int), - glob64_t *__pglob); - -#undef dirent -#define dirent __old_dirent64 -#undef GL_READDIR -# define GL_READDIR(pglob, stream) \ - ((struct __old_dirent64 *) (pglob)->gl_readdir (stream)) -#undef __readdir -#define __readdir(dirp) __old_readdir64 (dirp) -#undef glob -#define glob(pattern, flags, errfunc, pglob) \ - __old_glob64 (pattern, flags, errfunc, pglob) -#define convert_dirent __old_convert_dirent -#define glob_in_dir __old_glob_in_dir -#define GLOB_ATTRIBUTE attribute_compat_text_section - -#define GLOB_ONLY_P 1 - -#include - -compat_symbol (libc, __old_glob64, glob64, GLIBC_2_1); -#endif diff --git a/sysdeps/unix/sysv/linux/i386/vfork.S b/sysdeps/unix/sysv/linux/i386/vfork.S index 7a1d3373bb..a865de2201 100644 --- a/sysdeps/unix/sysv/linux/i386/vfork.S +++ b/sysdeps/unix/sysv/linux/i386/vfork.S @@ -34,17 +34,6 @@ ENTRY (__vfork) cfi_adjust_cfa_offset (-4) cfi_register (%eip, %ecx) - /* Save the TCB-cached PID away in %edx, and then negate the TCB - field. But if it's zero, set it to 0x80000000 instead. See - raise.c for the logic that relies on this value. */ - movl %gs:PID, %edx - movl %edx, %eax - negl %eax - jne 1f - movl $0x80000000, %eax -1: movl %eax, %gs:PID - - /* Stuff the syscall number in EAX and enter into the kernel. */ movl $SYS_ify (vfork), %eax int $0x80 @@ -55,14 +44,6 @@ ENTRY (__vfork) pushl %ecx cfi_adjust_cfa_offset (4) - /* Restore the original value of the TCB cache of the PID, if we're - the parent. But in the child (syscall return value equals zero), - leave things as they are. */ - testl %eax, %eax - je 1f - movl %edx, %gs:PID -1: - cmpl $-4095, %eax /* Branch forward if it failed. */ jae SYSCALL_ERROR_LABEL diff --git a/sysdeps/unix/sysv/linux/ia64/Makefile b/sysdeps/unix/sysv/linux/ia64/Makefile index 1de62c528a..4d6766db5e 100644 --- a/sysdeps/unix/sysv/linux/ia64/Makefile +++ b/sysdeps/unix/sysv/linux/ia64/Makefile @@ -19,6 +19,7 @@ endif ifeq ($(subdir),rt) librt-routines += rt-sysdep +librt-shared-only-routines += rt-sysdep endif ifeq ($(subdir),nptl) diff --git a/sysdeps/unix/sysv/linux/ia64/clone2.S b/sysdeps/unix/sysv/linux/ia64/clone2.S index b4cfdfc959..e637b6d4a5 100644 --- a/sysdeps/unix/sysv/linux/ia64/clone2.S +++ b/sysdeps/unix/sysv/linux/ia64/clone2.S @@ -67,19 +67,7 @@ ENTRY(__clone2) (CHILD) mov loc0=gp (PARENT) ret ;; - tbit.nz p6,p0=in3,8 /* CLONE_VM */ -(p6) br.cond.dptk 1f - ;; - mov r15=SYS_ify (getpid) -(p7) break __BREAK_SYSCALL - ;; - add r9=PID,r13 - add r10=TID,r13 - ;; - st4 [r9]=r8 - st4 [r10]=r8 - ;; -1: ld8 out1=[in0],8 /* Retrieve code pointer. */ + ld8 out1=[in0],8 /* Retrieve code pointer. */ mov out0=in4 /* Pass proper argument to fn */ ;; ld8 gp=[in0] /* Load function gp. */ diff --git a/sysdeps/unix/sysv/linux/ia64/vfork.S b/sysdeps/unix/sysv/linux/ia64/vfork.S index 9154d7c0fd..84bfdd5d8a 100644 --- a/sysdeps/unix/sysv/linux/ia64/vfork.S +++ b/sysdeps/unix/sysv/linux/ia64/vfork.S @@ -33,32 +33,12 @@ ENTRY (__libc_vfork) .prologue // work around a GAS bug which triggers if .body // first .prologue is not at the beginning of proc. alloc r2=ar.pfs,0,0,2,0 - adds r14=PID,r13 - ;; - ld4 r16=[r14] - ;; - sub r15=0,r16 - cmp.eq p6,p0=0,r16 - ;; -(p6) movl r15=0x80000000 mov out0=CLONE_VM+CLONE_VFORK+SIGCHLD mov out1=0 /* Standard sp value. */ ;; - st4 [r14]=r15 DO_CALL (SYS_ify (clone)) cmp.eq p6,p0=0,r8 - adds r14=PID,r13 (p6) br.cond.dptk 1f - ;; - ld4 r15=[r14] - ;; - extr.u r16=r15,0,31 - ;; - cmp.eq p0,p6=0,r16 - ;; -(p6) sub r16=0,r15 - ;; - st4 [r14]=r16 1: cmp.eq p6,p0=-1,r10 (p6) br.cond.spnt.few __syscall_error diff --git a/sysdeps/unix/sysv/linux/m68k/clone.S b/sysdeps/unix/sysv/linux/m68k/clone.S index 3a828443dc..630a29209d 100644 --- a/sysdeps/unix/sysv/linux/m68k/clone.S +++ b/sysdeps/unix/sysv/linux/m68k/clone.S @@ -98,19 +98,6 @@ ENTRY (__clone) cfi_startproc cfi_undefined (pc) /* Mark end of stack */ subl %fp, %fp /* terminate the stack frame */ - /* Check and see if we need to reset the PID. */ - andl #CLONE_VM, %d1 - jne 1f - movel #SYS_ify (getpid), %d0 - trap #0 - movel %a0, -(%sp) - movel %d0, -(%sp) - bsrl __m68k_read_tp@PLTPC - movel (%sp)+, %d0 - movel %d0, PID_OFFSET(%a0) - movel %d0, TID_OFFSET(%a0) - movel (%sp)+, %a0 -1: jsr (%a0) movel %d0, %d1 movel #SYS_ify (exit), %d0 diff --git a/sysdeps/unix/sysv/linux/m68k/vfork.S b/sysdeps/unix/sysv/linux/m68k/vfork.S index 1625a7b7a0..e27479361b 100644 --- a/sysdeps/unix/sysv/linux/m68k/vfork.S +++ b/sysdeps/unix/sysv/linux/m68k/vfork.S @@ -28,18 +28,6 @@ ENTRY (__vfork) - /* Save the TCB-cached PID away in %d1, and then negate the TCB - field. But if it's zero, set it to 0x80000000 instead. See - raise.c for the logic that relies on this value. */ - jbsr __m68k_read_tp@PLTPC - movel %a0, %a1 - movel PID_OFFSET(%a1), %d0 - movel %d0, %d1 - negl %d0 - jne 1f - movel #0x80000000, %d0 -1: movel %d0, PID_OFFSET(%a1) - /* Pop the return PC value into A0. */ movel %sp@+, %a0 cfi_adjust_cfa_offset (-4) @@ -49,14 +37,6 @@ ENTRY (__vfork) movel #SYS_ify (vfork), %d0 trap #0 - /* Restore the original value of the TCB cache of the PID, if we're - the parent. But in the child (syscall return value equals zero), - leave things as they are. */ - tstl %d0 - jeq 1f - movel %d1, PID_OFFSET(%a1) -1: - tstl %d0 jmi .Lerror /* Branch forward if it failed. */ diff --git a/sysdeps/unix/sysv/linux/microblaze/Makefile b/sysdeps/unix/sysv/linux/microblaze/Makefile index 44a838fa11..d178bc6f34 100644 --- a/sysdeps/unix/sysv/linux/microblaze/Makefile +++ b/sysdeps/unix/sysv/linux/microblaze/Makefile @@ -5,4 +5,5 @@ endif ifeq ($(subdir),nptl) # pull in __syscall_error routine libpthread-routines += sysdep -endif \ No newline at end of file +libpthread-shared-only-routines += sysdep +endif diff --git a/sysdeps/unix/sysv/linux/mips/clone.S b/sysdeps/unix/sysv/linux/mips/clone.S index 39634c5cf0..7ae65ef723 100644 --- a/sysdeps/unix/sysv/linux/mips/clone.S +++ b/sysdeps/unix/sysv/linux/mips/clone.S @@ -130,11 +130,6 @@ L(thread_start): SAVE_GP (GPOFF) /* The stackframe has been created on entry of clone(). */ - /* Check and see if we need to reset the PID. */ - and a1,a0,CLONE_VM - beqz a1,L(restore_pid) -L(donepid): - /* Restore the arg for user's function. */ PTR_L t9,0(sp) /* Function pointer. */ PTR_L a0,PTRSIZE(sp) /* Argument pointer. */ @@ -151,14 +146,6 @@ L(donepid): jal _exit #endif -L(restore_pid): - li v0,__NR_getpid - syscall - READ_THREAD_POINTER(v1) - INT_S v0,PID_OFFSET(v1) - INT_S v0,TID_OFFSET(v1) - b L(donepid) - END(__thread_start) libc_hidden_def (__clone) diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/globfree64.c b/sysdeps/unix/sysv/linux/mips/mips64/n64/globfree64.c new file mode 100644 index 0000000000..abc35fdd2b --- /dev/null +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/globfree64.c @@ -0,0 +1 @@ +/* glob64 is in globfree64.c */ diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/syscalls.list b/sysdeps/unix/sysv/linux/mips/mips64/n64/syscalls.list index 890a74494a..26ab6d0b75 100644 --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/syscalls.list +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/syscalls.list @@ -4,6 +4,8 @@ mmap - mmap b:aniiii __mmap mmap __mmap64 mmap64 sync_file_range - sync_file_range Ci:iiii sync_file_range +readahead - readahead i:iii __readahead readahead + prlimit EXTRA prlimit64 i:iipp prlimit prlimit64 fanotify_mark EXTRA fanotify_mark i:iiiis fanotify_mark diff --git a/sysdeps/unix/sysv/linux/mips/vfork.S b/sysdeps/unix/sysv/linux/mips/vfork.S index 1867c8626e..0b9244b7f8 100644 --- a/sysdeps/unix/sysv/linux/mips/vfork.S +++ b/sysdeps/unix/sysv/linux/mips/vfork.S @@ -60,14 +60,6 @@ NESTED(__libc_vfork,FRAMESZ,sp) PTR_ADDU sp, FRAMESZ cfi_adjust_cfa_offset (-FRAMESZ) - /* Save the PID value. */ - READ_THREAD_POINTER(v1) /* Get the thread pointer. */ - lw a2, PID_OFFSET(v1) /* Load the saved PID. */ - subu a2, $0, a2 /* Negate it. */ - bnez a2, 1f /* If it was zero... */ - lui a2, 0x8000 /* use 0x80000000 instead. */ -1: sw a2, PID_OFFSET(v1) /* Store the temporary PID. */ - li a0, 0x4112 /* CLONE_VM | CLONE_VFORK | SIGCHLD */ move a1, sp @@ -75,17 +67,6 @@ NESTED(__libc_vfork,FRAMESZ,sp) li v0,__NR_clone syscall - /* Restore the old PID value in the parent. */ - beqz v0, 1f /* If we are the parent... */ - READ_THREAD_POINTER(v1) /* Get the thread pointer. */ - lw a2, PID_OFFSET(v1) /* Load the saved PID. */ - subu a2, $0, a2 /* Re-negate it. */ - lui a0, 0x8000 /* Load 0x80000000... */ - bne a2, a0, 2f /* ... compare against it... */ - li a2, 0 /* ... use 0 instead. */ -2: sw a2, PID_OFFSET(v1) /* Restore the PID. */ -1: - cfi_remember_state bnez a3,L(error) diff --git a/sysdeps/unix/sysv/linux/nios2/clone.S b/sysdeps/unix/sysv/linux/nios2/clone.S index 30b6e4a6c8..c9fa00f94c 100644 --- a/sysdeps/unix/sysv/linux/nios2/clone.S +++ b/sysdeps/unix/sysv/linux/nios2/clone.S @@ -68,14 +68,6 @@ thread_start: cfi_startproc cfi_undefined (ra) - /* We expect the argument registers to be preserved across system - calls and across task cloning, so flags should be in r4 here. */ - andi r2, r4, CLONE_VM - bne r2, zero, 2f - DO_CALL (getpid, 0) - stw r2, PID_OFFSET(r23) - stw r2, TID_OFFSET(r23) -2: ldw r5, 4(sp) /* Function pointer. */ ldw r4, 0(sp) /* Argument pointer. */ addi sp, sp, 8 diff --git a/sysdeps/unix/sysv/linux/nios2/vfork.S b/sysdeps/unix/sysv/linux/nios2/vfork.S index c1bb9c7134..8997269199 100644 --- a/sysdeps/unix/sysv/linux/nios2/vfork.S +++ b/sysdeps/unix/sysv/linux/nios2/vfork.S @@ -21,20 +21,10 @@ ENTRY(__vfork) - ldw r6, PID_OFFSET(r23) - sub r7, zero, r6 - bne r7, zero, 2f - movhi r7, %hi(0x80000000) -2: - stw r7, PID_OFFSET(r23) - movi r4, 0x4111 /* (CLONE_VM | CLONE_VFORK | SIGCHLD) */ mov r5, zero DO_CALL (clone, 2) - beq r2, zero, 1f - stw r6, PID_OFFSET(r23) -1: bne r7, zero, SYSCALL_ERROR_LABEL ret diff --git a/sysdeps/unix/sysv/linux/oldglob.c b/sysdeps/unix/sysv/linux/oldglob.c new file mode 100644 index 0000000000..8233e57ce9 --- /dev/null +++ b/sysdeps/unix/sysv/linux/oldglob.c @@ -0,0 +1,42 @@ +#include + +#if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2) + +#include +#include +#include + +#include + +int __old_glob64 (const char *__pattern, int __flags, + int (*__errfunc) (const char *, int), + glob64_t *__pglob); +libc_hidden_proto (__old_glob64); + +#define dirent __old_dirent64 +#define GL_READDIR(pglob, stream) \ + ((struct __old_dirent64 *) (pglob)->gl_readdir (stream)) +#undef __readdir +#define __readdir(dirp) __old_readdir64 (dirp) + +#define glob_t glob64_t +#define glob(pattern, flags, errfunc, pglob) \ + __old_glob64 (pattern, flags, errfunc, pglob) +#define globfree(pglob) globfree64(pglob) + +#define convert_dirent __old_convert_dirent +#define glob_in_dir __old_glob_in_dir + +#undef stat +#define stat stat64 +#undef __stat +#define __stat(file, buf) __xstat64 (_STAT_VER, file, buf) + +#define GLOB_ATTRIBUTE attribute_compat_text_section + +#include + +libc_hidden_def (__old_glob64); + +compat_symbol (libc, __old_glob64, glob64, GLIBC_2_1); +#endif diff --git a/sysdeps/unix/sysv/linux/powerpc/Makefile b/sysdeps/unix/sysv/linux/powerpc/Makefile index c89ed9ec7d..2cfb46eca3 100644 --- a/sysdeps/unix/sysv/linux/powerpc/Makefile +++ b/sysdeps/unix/sysv/linux/powerpc/Makefile @@ -8,6 +8,7 @@ abi-64-v2-condition := __WORDSIZE == 64 && _CALL_ELF == 2 ifeq ($(subdir),rt) librt-routines += rt-sysdep +librt-shared-only-routines += rt-sysdep endif ifeq ($(subdir),stdlib) @@ -34,4 +35,5 @@ ifeq ($(subdir),nptl) libpthread-routines += sysdep libpthread-sysdep_routines += elision-lock elision-unlock elision-timed \ elision-trylock +libpthread-shared-only-routines += sysdep endif diff --git a/sysdeps/unix/sysv/linux/powerpc/elision-lock.c b/sysdeps/unix/sysv/linux/powerpc/elision-lock.c index dd1e4c3b17..7dd3d835b6 100644 --- a/sysdeps/unix/sysv/linux/powerpc/elision-lock.c +++ b/sysdeps/unix/sysv/linux/powerpc/elision-lock.c @@ -45,7 +45,9 @@ int __lll_lock_elision (int *lock, short *adapt_count, EXTRAARG int pshared) { - if (*adapt_count > 0) + /* adapt_count is accessed concurrently but is just a hint. Thus, + use atomic accesses but relaxed MO is sufficient. */ + if (atomic_load_relaxed (adapt_count) > 0) { goto use_lock; } @@ -67,7 +69,8 @@ __lll_lock_elision (int *lock, short *adapt_count, EXTRAARG int pshared) if (_TEXASRU_FAILURE_PERSISTENT (__builtin_get_texasru ())) { if (aconf.skip_lock_internal_abort > 0) - *adapt_count = aconf.skip_lock_internal_abort; + atomic_store_relaxed (adapt_count, + aconf.skip_lock_internal_abort); goto use_lock; } } @@ -75,7 +78,8 @@ __lll_lock_elision (int *lock, short *adapt_count, EXTRAARG int pshared) /* Fall back to locks for a bit if retries have been exhausted */ if (aconf.try_tbegin > 0 && aconf.skip_lock_out_of_tbegin_retries > 0) - *adapt_count = aconf.skip_lock_out_of_tbegin_retries; + atomic_store_relaxed (adapt_count, + aconf.skip_lock_out_of_tbegin_retries); use_lock: return LLL_LOCK ((*lock), pshared); diff --git a/sysdeps/unix/sysv/linux/powerpc/elision-trylock.c b/sysdeps/unix/sysv/linux/powerpc/elision-trylock.c index 0807a6a432..606185670d 100644 --- a/sysdeps/unix/sysv/linux/powerpc/elision-trylock.c +++ b/sysdeps/unix/sysv/linux/powerpc/elision-trylock.c @@ -34,7 +34,7 @@ __lll_trylock_elision (int *futex, short *adapt_count) __libc_tabort (_ABORT_NESTED_TRYLOCK); /* Only try a transaction if it's worth it. */ - if (*adapt_count > 0) + if (atomic_load_relaxed (adapt_count) > 0) { goto use_lock; } @@ -49,7 +49,7 @@ __lll_trylock_elision (int *futex, short *adapt_count) __libc_tend (0); if (aconf.skip_lock_busy > 0) - *adapt_count = aconf.skip_lock_busy; + atomic_store_relaxed (adapt_count, aconf.skip_lock_busy); } else { @@ -59,7 +59,8 @@ __lll_trylock_elision (int *futex, short *adapt_count) result in another failure. Use normal locking now and for the next couple of calls. */ if (aconf.skip_trylock_internal_abort > 0) - *adapt_count = aconf.skip_trylock_internal_abort; + atomic_store_relaxed (adapt_count, + aconf.skip_trylock_internal_abort); } } diff --git a/sysdeps/unix/sysv/linux/powerpc/elision-unlock.c b/sysdeps/unix/sysv/linux/powerpc/elision-unlock.c index 43c5a67df2..51d7018e4c 100644 --- a/sysdeps/unix/sysv/linux/powerpc/elision-unlock.c +++ b/sysdeps/unix/sysv/linux/powerpc/elision-unlock.c @@ -28,13 +28,16 @@ __lll_unlock_elision (int *lock, short *adapt_count, int pshared) __libc_tend (0); else { - lll_unlock ((*lock), pshared); + /* Update adapt_count in the critical section to prevent a + write-after-destroy error as mentioned in BZ 20822. The + following update of adapt_count has to be contained within + the critical region of the fall-back lock in order to not violate + the mutex destruction requirements. */ + short __tmp = atomic_load_relaxed (adapt_count); + if (__tmp > 0) + atomic_store_relaxed (adapt_count, __tmp - 1); - /* Update the adapt count AFTER completing the critical section. - Doing this here prevents unneeded stalling when entering - a critical section. Saving about 8% runtime on P8. */ - if (*adapt_count > 0) - (*adapt_count)--; + lll_unlock ((*lock), pshared); } return 0; } diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/clone.S b/sysdeps/unix/sysv/linux/powerpc/powerpc32/clone.S index bebadbfbb9..49fe01ecde 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/clone.S +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/clone.S @@ -76,15 +76,6 @@ ENTRY (__clone) crandc cr1*4+eq,cr1*4+eq,cr0*4+so bne- cr1,L(parent) /* The '-' is to minimise the race. */ - /* If CLONE_VM is set do not update the pid/tid field. */ - andi. r0,r28,CLONE_VM - bne+ cr0,L(oldpid) - - DO_CALL(SYS_ify(getpid)) - stw r3,TID(r2) - stw r3,PID(r2) -L(oldpid): - /* Call procedure. */ mtctr r30 mr r3,r31 diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S b/sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S index edbc7de1e6..0a724953a4 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S @@ -27,34 +27,8 @@ ENTRY (__vfork) - /* Load the TCB-cached PID value and negates it. If It it is zero - sets it to 0x800000. And then sets its value again on TCB field. - See raise.c for the logic that relies on this value. */ - - lwz r0,PID(r2) - cmpwi cr0,r0,0 - neg r0,r0 - bne- cr0,1f - lis r0,0x8000 -1: stw r0,PID(r2) - DO_CALL (SYS_ify (vfork)) - cmpwi cr1,r3,0 - beqlr- 1 - - /* Restore the original value of the TCB cache of the PID, if we're - the parent. But in the child (syscall return value equals zero), - leave things as they are. */ - lwz r0,PID(r2) - /* Cannot use clrlwi. here, because cr0 needs to be preserved - until PSEUDO_RET. */ - clrlwi r4,r0,1 - cmpwi cr1,r4,0 - beq- cr1,1f - neg r4,r0 -1: stw r4,PID(r2) - PSEUDO_RET PSEUDO_END (__vfork) diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S b/sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S index 7c59b9b4e9..d8604f6731 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S @@ -78,15 +78,6 @@ ENTRY (__clone) crandc cr1*4+eq,cr1*4+eq,cr0*4+so bne- cr1,L(parent) /* The '-' is to minimise the race. */ - /* If CLONE_VM is set do not update the pid/tid field. */ - rldicl. r0,r29,56,63 /* flags & CLONE_VM. */ - bne+ cr0,L(oldpid) - - DO_CALL(SYS_ify(getpid)) - stw r3,TID(r13) - stw r3,PID(r13) -L(oldpid): - std r2,FRAME_TOC_SAVE(r1) /* Call procedure. */ PPC64_LOAD_FUNCPTR r30 diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/vfork.S b/sysdeps/unix/sysv/linux/powerpc/powerpc64/vfork.S index 3083ab7b3c..6b4cf432c1 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/vfork.S +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/vfork.S @@ -28,31 +28,8 @@ ENTRY (__vfork) CALL_MCOUNT 0 - /* Load the TCB-cached PID value and negates it. If It it is zero - sets it to 0x800000. And then sets its value again on TCB field. - See raise.c for the logic that relies on this value. */ - lwz r0,PID(r13) - cmpwi cr0,r0,0 - neg r0,r0 - bne- cr0,1f - lis r0,0x8000 -1: stw r0,PID(r13) - DO_CALL (SYS_ify (vfork)) - cmpwi cr1,r3,0 - beqlr- 1 - - /* Restore the original value of the TCB cache of the PID, if we're - the parent. But in the child (syscall return value equals zero), - leave things as they are. */ - lwz r0,PID(r13) - clrlwi r4,r0,1 - cmpwi cr1,r4,0 - beq- cr1,1f - neg r4,r0 -1: stw r4,PID(r13) - PSEUDO_RET PSEUDO_END (__vfork) diff --git a/sysdeps/unix/sysv/linux/pread.c b/sysdeps/unix/sysv/linux/pread.c index 1bcff64781..46d974d952 100644 --- a/sysdeps/unix/sysv/linux/pread.c +++ b/sysdeps/unix/sysv/linux/pread.c @@ -28,8 +28,7 @@ ssize_t __libc_pread (int fd, void *buf, size_t count, off_t offset) { - return SYSCALL_CANCEL (pread, fd, buf, count, - __ALIGNMENT_ARG SYSCALL_LL (offset)); + return SYSCALL_CANCEL (pread, fd, buf, count, SYSCALL_LL_PRW (offset)); } strong_alias (__libc_pread, __pread) diff --git a/sysdeps/unix/sysv/linux/pread64.c b/sysdeps/unix/sysv/linux/pread64.c index 58c6aeb541..f51beae77a 100644 --- a/sysdeps/unix/sysv/linux/pread64.c +++ b/sysdeps/unix/sysv/linux/pread64.c @@ -26,8 +26,7 @@ ssize_t __libc_pread64 (int fd, void *buf, size_t count, off64_t offset) { - return SYSCALL_CANCEL (pread64, fd, buf, count, - __ALIGNMENT_ARG SYSCALL_LL64 (offset)); + return SYSCALL_CANCEL (pread64, fd, buf, count, SYSCALL_LL64_PRW (offset)); } weak_alias (__libc_pread64, __pread64) diff --git a/sysdeps/unix/sysv/linux/pthread-pids.h b/sysdeps/unix/sysv/linux/pthread-pids.h index d42bba03cf..618a5b1b9f 100644 --- a/sysdeps/unix/sysv/linux/pthread-pids.h +++ b/sysdeps/unix/sysv/linux/pthread-pids.h @@ -26,5 +26,5 @@ static inline void __pthread_initialize_pids (struct pthread *pd) { INTERNAL_SYSCALL_DECL (err); - pd->pid = pd->tid = INTERNAL_SYSCALL (set_tid_address, err, 1, &pd->tid); + pd->tid = INTERNAL_SYSCALL_CALL (set_tid_address, err, &pd->tid); } diff --git a/sysdeps/unix/sysv/linux/pthread_kill.c b/sysdeps/unix/sysv/linux/pthread_kill.c index bcb3009675..cc109973cc 100644 --- a/sysdeps/unix/sysv/linux/pthread_kill.c +++ b/sysdeps/unix/sysv/linux/pthread_kill.c @@ -21,6 +21,7 @@ #include #include #include +#include int @@ -49,15 +50,9 @@ __pthread_kill (pthread_t threadid, int signo) /* We have a special syscall to do the work. */ INTERNAL_SYSCALL_DECL (err); - /* One comment: The PID field in the TCB can temporarily be changed - (in fork). But this must not affect this code here. Since this - function would have to be called while the thread is executing - fork, it would have to happen in a signal handler. But this is - no allowed, pthread_kill is not guaranteed to be async-safe. */ - int val; - val = INTERNAL_SYSCALL (tgkill, err, 3, THREAD_GETMEM (THREAD_SELF, pid), - tid, signo); + pid_t pid = __getpid (); + int val = INTERNAL_SYSCALL_CALL (tgkill, err, pid, tid, signo); return (INTERNAL_SYSCALL_ERROR_P (val, err) ? INTERNAL_SYSCALL_ERRNO (val, err) : 0); } diff --git a/sysdeps/unix/sysv/linux/pthread_sigqueue.c b/sysdeps/unix/sysv/linux/pthread_sigqueue.c index 7694d5467c..e393e0bd73 100644 --- a/sysdeps/unix/sysv/linux/pthread_sigqueue.c +++ b/sysdeps/unix/sysv/linux/pthread_sigqueue.c @@ -49,27 +49,22 @@ pthread_sigqueue (pthread_t threadid, int signo, const union sigval value) if (signo == SIGCANCEL || signo == SIGTIMER || signo == SIGSETXID) return EINVAL; + pid_t pid = getpid (); + /* Set up the siginfo_t structure. */ siginfo_t info; memset (&info, '\0', sizeof (siginfo_t)); info.si_signo = signo; info.si_code = SI_QUEUE; - info.si_pid = THREAD_GETMEM (THREAD_SELF, pid); + info.si_pid = pid; info.si_uid = getuid (); info.si_value = value; /* We have a special syscall to do the work. */ INTERNAL_SYSCALL_DECL (err); - /* One comment: The PID field in the TCB can temporarily be changed - (in fork). But this must not affect this code here. Since this - function would have to be called while the thread is executing - fork, it would have to happen in a signal handler. But this is - no allowed, pthread_sigqueue is not guaranteed to be async-safe. */ - int val = INTERNAL_SYSCALL (rt_tgsigqueueinfo, err, 4, - THREAD_GETMEM (THREAD_SELF, pid), - tid, signo, &info); - + int val = INTERNAL_SYSCALL_CALL (rt_tgsigqueueinfo, err, pid, tid, signo, + &info); return (INTERNAL_SYSCALL_ERROR_P (val, err) ? INTERNAL_SYSCALL_ERRNO (val, err) : 0); #else diff --git a/sysdeps/unix/sysv/linux/pwrite.c b/sysdeps/unix/sysv/linux/pwrite.c index 9c502beac1..1371df8a60 100644 --- a/sysdeps/unix/sysv/linux/pwrite.c +++ b/sysdeps/unix/sysv/linux/pwrite.c @@ -28,8 +28,7 @@ ssize_t __libc_pwrite (int fd, const void *buf, size_t count, off_t offset) { - return SYSCALL_CANCEL (pwrite, fd, buf, count, - __ALIGNMENT_ARG SYSCALL_LL (offset)); + return SYSCALL_CANCEL (pwrite, fd, buf, count, SYSCALL_LL_PRW (offset)); } strong_alias (__libc_pwrite, __pwrite) diff --git a/sysdeps/unix/sysv/linux/pwrite64.c b/sysdeps/unix/sysv/linux/pwrite64.c index b49e6bc286..22f1f05a44 100644 --- a/sysdeps/unix/sysv/linux/pwrite64.c +++ b/sysdeps/unix/sysv/linux/pwrite64.c @@ -26,8 +26,7 @@ ssize_t __libc_pwrite64 (int fd, const void *buf, size_t count, off64_t offset) { - return SYSCALL_CANCEL (pwrite64, fd, buf, count, - __ALIGNMENT_ARG SYSCALL_LL64 (offset)); + return SYSCALL_CANCEL (pwrite64, fd, buf, count, SYSCALL_LL64_PRW (offset)); } weak_alias (__libc_pwrite64, __pwrite64) libc_hidden_weak (__pwrite64) diff --git a/sysdeps/unix/sysv/linux/raise.c b/sysdeps/unix/sysv/linux/raise.c index 470033e83d..49bb7cb0d4 100644 --- a/sysdeps/unix/sysv/linux/raise.c +++ b/sysdeps/unix/sysv/linux/raise.c @@ -26,13 +26,6 @@ int raise (int sig) { - /* raise is an async-safe function so it could be called while the - fork/vfork function temporarily invalidated the PID field. To avoid - relying on cached value we block all user-defined signal handler - (which might call fork/vfork) and issue the getpid and gettid - syscalls directly. */ - - /* rt_sigprocmask may fail if: 1. sigsetsize != sizeof (sigset_t) (EINVAL) diff --git a/sysdeps/unix/sysv/linux/s390/Makefile b/sysdeps/unix/sysv/linux/s390/Makefile index 497ffd566c..f8ed013e9e 100644 --- a/sysdeps/unix/sysv/linux/s390/Makefile +++ b/sysdeps/unix/sysv/linux/s390/Makefile @@ -6,6 +6,7 @@ abi-64-condition := __WORDSIZE == 64 ifeq ($(subdir),rt) librt-routines += rt-sysdep +librt-shared-only-routines += rt-sysdep endif ifeq ($(subdir),stdlib) diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/clone.S b/sysdeps/unix/sysv/linux/s390/s390-32/clone.S index 2f8fa0b840..b1de1480d1 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-32/clone.S +++ b/sysdeps/unix/sysv/linux/s390/s390-32/clone.S @@ -54,13 +54,6 @@ error: PSEUDO_END (__clone) thread_start: - tml %r3,256 /* CLONE_VM == 0x00000100 */ - jne 1f - svc SYS_ify(getpid) - ear %r3,%a0 - st %r2,PID(%r3) - st %r2,TID(%r3) -1: /* fn is in gpr 1, arg in gpr 0 */ lr %r2,%r0 /* set first parameter to void *arg */ ahi %r15,-96 /* make room on the stack for the save area */ diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/vfork.S b/sysdeps/unix/sysv/linux/s390/s390-32/vfork.S index b7588ebd7c..cc60e139ba 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-32/vfork.S +++ b/sysdeps/unix/sysv/linux/s390/s390-32/vfork.S @@ -28,21 +28,9 @@ and the process ID of the new process to the old process. */ ENTRY (__libc_vfork) - ear %r4,%a0 - lhi %r1,1 - icm %r3,15,PID(%r4) - sll %r1,31 - je 1f - lcr %r1,%r3 -1: st %r1,PID(%r4) - /* Do vfork system call. */ svc SYS_ify (vfork) - ltr %r2,%r2 - je 1f - st %r3,PID(%r4) -1: /* Check for error. */ lhi %r4,-4095 clr %r2,%r4 diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/clone.S b/sysdeps/unix/sysv/linux/s390/s390-64/clone.S index fb816922ca..29606acf03 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-64/clone.S +++ b/sysdeps/unix/sysv/linux/s390/s390-64/clone.S @@ -55,15 +55,6 @@ error: PSEUDO_END (__clone) thread_start: - tmll %r3,256 /* CLONE_VM == 0x00000100 */ - jne 1f - svc SYS_ify(getpid) - ear %r3,%a0 - sllg %r3,%r3,32 - ear %r3,%a1 - st %r2,PID(%r3) - st %r2,TID(%r3) -1: /* fn is in gpr 1, arg in gpr 0 */ lgr %r2,%r0 /* set first parameter to void *arg */ aghi %r15,-160 /* make room on the stack for the save area */ diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/vfork.S b/sysdeps/unix/sysv/linux/s390/s390-64/vfork.S index 0bd2161381..b9a813f2cc 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-64/vfork.S +++ b/sysdeps/unix/sysv/linux/s390/s390-64/vfork.S @@ -28,22 +28,9 @@ and the process ID of the new process to the old process. */ ENTRY (__libc_vfork) - ear %r4,%a0 - sllg %r4,%r4,32 - ear %r4,%a1 - icm %r3,15,PID(%r4) - llilh %r1,32768 - je 1f - lcr %r1,%r3 -1: st %r1,PID(%r4) - /* Do vfork system call. */ svc SYS_ify (vfork) - ltgr %r2,%r2 - je 1f - st %r3,PID(%r4) -1: /* Check for error. */ lghi %r4,-4095 clgr %r2,%r4 diff --git a/sysdeps/unix/sysv/linux/sh/clone.S b/sysdeps/unix/sysv/linux/sh/clone.S index 4cd7df117c..ce7cddcb19 100644 --- a/sysdeps/unix/sysv/linux/sh/clone.S +++ b/sysdeps/unix/sysv/linux/sh/clone.S @@ -66,23 +66,7 @@ ENTRY(__clone) 2: /* terminate the stack frame */ mov #0, r14 - mov r4, r0 - shlr8 r0 - tst #1, r0 // CLONE_VM = (1 << 8) - bf/s 4f - mov r4, r0 - /* new pid */ - mov #+SYS_ify(getpid), r3 - trapa #0x15 -3: - stc gbr, r1 - mov.w .Lpidoff, r2 - add r1, r2 - mov.l r0, @r2 - mov.w .Ltidoff, r2 - add r1, r2 - mov.l r0, @r2 -4: + /* thread starts */ mov.l @r15, r1 jsr @r1 @@ -113,10 +97,6 @@ ENTRY(__clone) .long _GLOBAL_OFFSET_TABLE_ .L3: .long PLTJMP(C_SYMBOL_NAME(_exit)) -.Lpidoff: - .word PID - TLS_PRE_TCB_SIZE -.Ltidoff: - .word TID - TLS_PRE_TCB_SIZE PSEUDO_END (__clone) libc_hidden_def (__clone) diff --git a/sysdeps/unix/sysv/linux/sh/kernel-features.h b/sysdeps/unix/sysv/linux/sh/kernel-features.h index ad05fc39e1..c5240fafbd 100644 --- a/sysdeps/unix/sysv/linux/sh/kernel-features.h +++ b/sysdeps/unix/sysv/linux/sh/kernel-features.h @@ -44,3 +44,8 @@ /* SH does not have a 64-bit inode field. */ #undef __ASSUME_ST_INO_64_BIT + +/* SH4 ABI does not really require argument alignment for 64-bits, but + the kernel interface for p{read,write}64 adds a dummy long argument + before the offset. */ +#define __ASSUME_PRW_DUMMY_ARG 1 diff --git a/sysdeps/unix/sysv/linux/sh/pwrite.c b/sysdeps/unix/sysv/linux/sh/pwrite.c deleted file mode 100644 index 391ed5e17b..0000000000 --- a/sysdeps/unix/sysv/linux/sh/pwrite.c +++ /dev/null @@ -1,23 +0,0 @@ -/* Copyright (C) 1997-2016 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1997. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - . */ - -/* SH4 ABI does not really require argument alignment for 64-bits, but - the kernel interface for pwrite adds a dummy long argument before the - offset. */ -#define __ALIGNMENT_ARG -#include diff --git a/sysdeps/unix/sysv/linux/sh/sh3/ucontext_i.sym b/sysdeps/unix/sysv/linux/sh/sh3/ucontext_i.sym index 17397c5511..25f914a93b 100644 --- a/sysdeps/unix/sysv/linux/sh/sh3/ucontext_i.sym +++ b/sysdeps/unix/sysv/linux/sh/sh3/ucontext_i.sym @@ -13,22 +13,22 @@ SIG_SETMASK oLINK ucontext (uc_link) oSS_SP ucontext (uc_stack.ss_sp) oSS_SIZE ucontext (uc_stack.ss_size) -oR0 mcontext (gregs[R0]) -oR1 mcontext (gregs[R1]) -oR2 mcontext (gregs[R2]) -oR3 mcontext (gregs[R3]) -oR4 mcontext (gregs[R4]) -oR5 mcontext (gregs[R5]) -oR6 mcontext (gregs[R6]) -oR7 mcontext (gregs[R7]) -oR8 mcontext (gregs[R8]) -oR9 mcontext (gregs[R9]) -oR10 mcontext (gregs[R10]) -oR11 mcontext (gregs[R11]) -oR12 mcontext (gregs[R12]) -oR13 mcontext (gregs[R13]) -oR14 mcontext (gregs[R14]) -oR15 mcontext (gregs[R15]) +oR0 mcontext (gregs[REG_R0]) +oR1 mcontext (gregs[REG_R1]) +oR2 mcontext (gregs[REG_R2]) +oR3 mcontext (gregs[REG_R3]) +oR4 mcontext (gregs[REG_R4]) +oR5 mcontext (gregs[REG_R5]) +oR6 mcontext (gregs[REG_R6]) +oR7 mcontext (gregs[REG_R7]) +oR8 mcontext (gregs[REG_R8]) +oR9 mcontext (gregs[REG_R9]) +oR10 mcontext (gregs[REG_R10]) +oR11 mcontext (gregs[REG_R11]) +oR12 mcontext (gregs[REG_R12]) +oR13 mcontext (gregs[REG_R13]) +oR14 mcontext (gregs[REG_R14]) +oR15 mcontext (gregs[REG_R15]) oPC mcontext (pc) oPR mcontext (pr) oSR mcontext (sr) diff --git a/sysdeps/unix/sysv/linux/sh/sh4/ucontext_i.sym b/sysdeps/unix/sysv/linux/sh/sh4/ucontext_i.sym index 65633fbcf4..130f60cd96 100644 --- a/sysdeps/unix/sysv/linux/sh/sh4/ucontext_i.sym +++ b/sysdeps/unix/sysv/linux/sh/sh4/ucontext_i.sym @@ -13,22 +13,22 @@ SIG_SETMASK oLINK ucontext (uc_link) oSS_SP ucontext (uc_stack.ss_sp) oSS_SIZE ucontext (uc_stack.ss_size) -oR0 mcontext (gregs[R0]) -oR1 mcontext (gregs[R1]) -oR2 mcontext (gregs[R2]) -oR3 mcontext (gregs[R3]) -oR4 mcontext (gregs[R4]) -oR5 mcontext (gregs[R5]) -oR6 mcontext (gregs[R6]) -oR7 mcontext (gregs[R7]) -oR8 mcontext (gregs[R8]) -oR9 mcontext (gregs[R9]) -oR10 mcontext (gregs[R10]) -oR11 mcontext (gregs[R11]) -oR12 mcontext (gregs[R12]) -oR13 mcontext (gregs[R13]) -oR14 mcontext (gregs[R14]) -oR15 mcontext (gregs[R15]) +oR0 mcontext (gregs[REG_R0]) +oR1 mcontext (gregs[REG_R1]) +oR2 mcontext (gregs[REG_R2]) +oR3 mcontext (gregs[REG_R3]) +oR4 mcontext (gregs[REG_R4]) +oR5 mcontext (gregs[REG_R5]) +oR6 mcontext (gregs[REG_R6]) +oR7 mcontext (gregs[REG_R7]) +oR8 mcontext (gregs[REG_R8]) +oR9 mcontext (gregs[REG_R9]) +oR10 mcontext (gregs[REG_R10]) +oR11 mcontext (gregs[REG_R11]) +oR12 mcontext (gregs[REG_R12]) +oR13 mcontext (gregs[REG_R13]) +oR14 mcontext (gregs[REG_R14]) +oR15 mcontext (gregs[REG_R15]) oPC mcontext (pc) oPR mcontext (pr) oSR mcontext (sr) diff --git a/sysdeps/unix/sysv/linux/sh/sys/ucontext.h b/sysdeps/unix/sysv/linux/sh/sys/ucontext.h index ab9a7e66bf..037fbb73e8 100644 --- a/sysdeps/unix/sysv/linux/sh/sys/ucontext.h +++ b/sysdeps/unix/sysv/linux/sh/sys/ucontext.h @@ -31,49 +31,47 @@ typedef int greg_t; /* Number of general registers. */ -#define NGPREG 16 +#define NGREG 16 /* Container for all general registers. */ -typedef greg_t gregset_t[NGPREG]; +typedef greg_t gregset_t[NGREG]; -#ifdef __USE_GNU /* Number of each register is the `gregset_t' array. */ enum { - R0 = 0, -#define R0 R0 - R1 = 1, -#define R1 R1 - R2 = 2, -#define R2 R2 - R3 = 3, -#define R3 R3 - R4 = 4, -#define R4 R4 - R5 = 5, -#define R5 R5 - R6 = 6, -#define R6 R6 - R7 = 7, -#define R7 R7 - R8 = 8, -#define R8 R8 - R9 = 9, -#define R9 R9 - R10 = 10, -#define R10 R10 - R11 = 11, -#define R11 R11 - R12 = 12, -#define R12 R12 - R13 = 13, -#define R13 R13 - R14 = 14, -#define R14 R14 - R15 = 15, -#define R15 R15 + REG_R0 = 0, +#define REG_R0 REG_R0 + REG_R1 = 1, +#define REG_R1 REG_R1 + REG_R2 = 2, +#define REG_R2 REG_R2 + REG_R3 = 3, +#define REG_R3 REG_R3 + REG_R4 = 4, +#define REG_R4 REG_R4 + REG_R5 = 5, +#define REG_R5 REG_R5 + REG_R6 = 6, +#define REG_R6 REG_R6 + REG_R7 = 7, +#define REG_R7 REG_R7 + REG_R8 = 8, +#define REG_R8 REG_R8 + REG_R9 = 9, +#define REG_R9 REG_R9 + REG_R10 = 10, +#define REG_R10 REG_R10 + REG_R11 = 11, +#define REG_R11 REG_R11 + REG_R12 = 12, +#define REG_R12 REG_R12 + REG_R13 = 13, +#define REG_R13 REG_R13 + REG_R14 = 14, +#define REG_R14 REG_R14 + REG_R15 = 15, +#define REG_R15 REG_R15 }; -#endif #if (defined(__SH4__) || defined(__SH4A__)) typedef int freg_t; diff --git a/sysdeps/unix/sysv/linux/sh/vfork.S b/sysdeps/unix/sysv/linux/sh/vfork.S index 6895bc5491..df559cb439 100644 --- a/sysdeps/unix/sysv/linux/sh/vfork.S +++ b/sysdeps/unix/sysv/linux/sh/vfork.S @@ -26,30 +26,11 @@ and the process ID of the new process to the old process. */ ENTRY (__libc_vfork) - /* Save the PID value. */ - stc gbr, r2 - mov.w .L2, r0 - mov.l @(r0,r2), r4 - neg r4, r1 - tst r1, r1 - bf 1f - mov #1, r1 - rotr r1 -1: - mov.l r1, @(r0,r2) mov.w .L1, r3 trapa #0x10 mov r0, r1 - /* Restore the old PID value in the parent. */ - tst r0, r0 - bt.s 2f - stc gbr, r2 - mov.w .L2, r0 - mov.l r4, @(r0,r2) - mov r1, r0 -2: mov #-12, r2 shad r2, r1 not r1, r1 // r1=0 means r0 = -1 to -4095 @@ -61,8 +42,6 @@ ENTRY (__libc_vfork) nop .L1: .word __NR_vfork -.L2: - .word PID - TLS_PRE_TCB_SIZE .align 2 PSEUDO_END (__libc_vfork) diff --git a/sysdeps/unix/sysv/linux/sparc/Makefile b/sysdeps/unix/sysv/linux/sparc/Makefile index e67aecf8f0..a67d199eb5 100644 --- a/sysdeps/unix/sysv/linux/sparc/Makefile +++ b/sysdeps/unix/sysv/linux/sparc/Makefile @@ -6,6 +6,7 @@ abi-64-condition := __WORDSIZE == 64 ifeq ($(subdir),rt) librt-routines += rt-sysdep +librt-shared-only-routines += rt-sysdep endif ifeq ($(subdir),sysvipc) @@ -15,4 +16,5 @@ endif ifeq ($(subdir),nptl) # pull in __syscall_error routine libpthread-routines += sysdep +libpthread-shared-only-routines += sysdep endif diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S b/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S index d6c92f6133..0456a0d16e 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S @@ -79,13 +79,6 @@ END(__clone) .type __thread_start,@function __thread_start: - andcc %g4, CLONE_VM, %g0 - bne 1f - set __NR_getpid,%g1 - ta 0x10 - st %o0,[%g7 + PID] - st %o0,[%g7 + TID] -1: mov %g0, %fp /* terminate backtrace */ call %g2 mov %g3,%o0 diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S b/sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S index 0d0a3b5298..6d985034f0 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S @@ -22,24 +22,14 @@ .text .globl __syscall_error ENTRY(__libc_vfork) - ld [%g7 + PID], %o5 - cmp %o5, 0 - bne 1f - sub %g0, %o5, %o4 - sethi %hi(0x80000000), %o4 -1: st %o4, [%g7 + PID] - LOADSYSCALL(vfork) ta 0x10 bcc 2f mov %o7, %g1 - st %o5, [%g7 + PID] call __syscall_error mov %g1, %o7 2: sub %o1, 1, %o1 andcc %o0, %o1, %o0 - bne,a 1f - st %o5, [%g7 + PID] 1: retl nop END(__libc_vfork) diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/clone.S b/sysdeps/unix/sysv/linux/sparc/sparc64/clone.S index b0f62660a7..6ffead88e2 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc64/clone.S +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/clone.S @@ -76,13 +76,6 @@ END(__clone) .type __thread_start,@function __thread_start: - andcc %g4, CLONE_VM, %g0 - bne,pt %icc, 1f - set __NR_getpid,%g1 - ta 0x6d - st %o0,[%g7 + PID] - st %o0,[%g7 + TID] -1: mov %g0, %fp /* terminate backtrace */ call %g2 mov %g3,%o0 diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S b/sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S index 0818eba02e..298dd197a9 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S @@ -22,24 +22,14 @@ .text .globl __syscall_error ENTRY(__libc_vfork) - ld [%g7 + PID], %o5 - sethi %hi(0x80000000), %o3 - cmp %o5, 0 - sub %g0, %o5, %o4 - move %icc, %o3, %o4 - st %o4, [%g7 + PID] - LOADSYSCALL(vfork) ta 0x6d bcc,pt %xcc, 2f mov %o7, %g1 - st %o5, [%g7 + PID] call __syscall_error mov %g1, %o7 2: sub %o1, 1, %o1 andcc %o0, %o1, %o0 - bne,a,pt %icc, 1f - st %o5, [%g7 + PID] 1: retl nop END(__libc_vfork) diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c index bb3eecfde1..b5f20a710b 100644 --- a/sysdeps/unix/sysv/linux/spawni.c +++ b/sysdeps/unix/sysv/linux/spawni.c @@ -58,22 +58,19 @@ normal program exit with the exit code 127. */ #define SPAWN_ERROR 127 -/* We need to block both SIGCANCEL and SIGSETXID. */ -#define SIGALL_SET \ - ((__sigset_t) { .__val = {[0 ... _SIGSET_NWORDS-1 ] = -1 } }) - #ifdef __ia64__ -# define CLONE(__fn, __stack, __stacksize, __flags, __args) \ - __clone2 (__fn, __stack, __stacksize, __flags, __args, 0, 0, 0) +# define CLONE(__fn, __stackbase, __stacksize, __flags, __args) \ + __clone2 (__fn, __stackbase, __stacksize, __flags, __args, 0, 0, 0) #else # define CLONE(__fn, __stack, __stacksize, __flags, __args) \ __clone (__fn, __stack, __flags, __args) #endif -#if _STACK_GROWS_DOWN -# define STACK(__stack, __stack_size) (__stack + __stack_size) -#elif _STACK_GROWS_UP +/* Since ia64 wants the stackbase w/clone2, re-use the grows-up macro. */ +#if _STACK_GROWS_UP || defined (__ia64__) # define STACK(__stack, __stack_size) (__stack) +#elif _STACK_GROWS_DOWN +# define STACK(__stack, __stack_size) (__stack + __stack_size) #endif @@ -329,6 +326,11 @@ __spawnix (pid_t * pid, const char *file, /* Add a slack area for child's stack. */ size_t argv_size = (argc * sizeof (void *)) + 512; + /* We need at least a few pages in case the compiler's stack checking is + enabled. In some configs, it is known to use at least 24KiB. We use + 32KiB to be "safe" from anything the compiler might do. Besides, the + extra pages won't actually be allocated unless they get used. */ + argv_size += (32 * 1024); size_t stack_size = ALIGN_UP (argv_size, GLRO(dl_pagesize)); void *stack = __mmap (NULL, stack_size, prot, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); @@ -340,7 +342,9 @@ __spawnix (pid_t * pid, const char *file, } /* Disable asynchronous cancellation. */ - int cs = LIBC_CANCEL_ASYNC (); + int state; + __libc_ptf_call (__pthread_setcancelstate, + (PTHREAD_CANCEL_DISABLE, &state), 0); args.file = file; args.exec = exec; @@ -351,7 +355,7 @@ __spawnix (pid_t * pid, const char *file, args.envp = envp; args.xflags = xflags; - __sigprocmask (SIG_BLOCK, &SIGALL_SET, &args.oldmask); + __libc_signal_block_all (&args.oldmask); /* The clone flags used will create a new child that will run in the same memory space (CLONE_VM) and the execution of calling thread will be @@ -384,9 +388,9 @@ __spawnix (pid_t * pid, const char *file, if ((ec == 0) && (pid != NULL)) *pid = new_pid; - __sigprocmask (SIG_SETMASK, &args.oldmask, 0); + __libc_signal_restore_set (&args.oldmask); - LIBC_CANCEL_RESET (cs); + __libc_ptf_call (__pthread_setcancelstate, (state, NULL), 0); return ec; } diff --git a/sysdeps/unix/sysv/linux/syscalls.list b/sysdeps/unix/sysv/linux/syscalls.list index 7ae2541f8f..248641b830 100644 --- a/sysdeps/unix/sysv/linux/syscalls.list +++ b/sysdeps/unix/sysv/linux/syscalls.list @@ -18,6 +18,7 @@ execve - execve i:spp __execve execve fdatasync - fdatasync Ci:i fdatasync flock - flock i:ii __flock flock get_kernel_syms EXTRA get_kernel_syms i:p __compat_get_kernel_syms get_kernel_syms@GLIBC_2.0:GLIBC_2.23 +getpid - getpid Ei: __getpid getpid getegid - getegid Ei: __getegid getegid geteuid - geteuid Ei: __geteuid geteuid getpgid - getpgid i:i __getpgid getpgid diff --git a/sysdeps/unix/sysv/linux/sysdep.h b/sysdeps/unix/sysv/linux/sysdep.h index a469f57121..e3ecd5638e 100644 --- a/sysdeps/unix/sysv/linux/sysdep.h +++ b/sysdeps/unix/sysv/linux/sysdep.h @@ -48,6 +48,16 @@ __LONG_LONG_PAIR ((long) ((val) >> 32), (long) ((val) & 0xffffffff)) #endif +/* Provide a common macro to pass 64-bit value on pread and pwrite + syscalls. */ +#ifdef __ASSUME_PRW_DUMMY_ARG +# define SYSCALL_LL_PRW(val) 0, SYSCALL_LL (val) +# define SYSCALL_LL64_PRW(val) 0, SYSCALL_LL64 (val) +#else +# define SYSCALL_LL_PRW(val) __ALIGNMENT_ARG SYSCALL_LL (val) +# define SYSCALL_LL64_PRW(val) __ALIGNMENT_ARG SYSCALL_LL64 (val) +#endif + /* Provide a macro to pass the off{64}_t argument on p{readv,writev}{64}. */ #define LO_HI_LONG(val) \ (long) (val), \ diff --git a/sysdeps/unix/sysv/linux/tile/Makefile b/sysdeps/unix/sysv/linux/tile/Makefile index 1c1cfff280..43acea3633 100644 --- a/sysdeps/unix/sysv/linux/tile/Makefile +++ b/sysdeps/unix/sysv/linux/tile/Makefile @@ -25,4 +25,5 @@ endif ifeq ($(subdir),nptl) # pull in __syscall_error routine libpthread-routines += sysdep +libpthread-shared-only-routines += sysdep endif diff --git a/sysdeps/unix/sysv/linux/tile/clone.S b/sysdeps/unix/sysv/linux/tile/clone.S index d1d36462e7..3f9e3d56c4 100644 --- a/sysdeps/unix/sysv/linux/tile/clone.S +++ b/sysdeps/unix/sysv/linux/tile/clone.S @@ -163,22 +163,6 @@ ENTRY (__clone) .Lthread_start: cfi_def_cfa_offset (FRAME_SIZE) cfi_undefined (lr) - /* Check and see if we need to reset the PID, which we do if - CLONE_VM isn't set, i.e. it's a fork-like clone with a new - address space. In that case we update the cached values - from the true system pid (retrieved via __NR_getpid syscall). */ - moveli r0, CLONE_VM - and r0, r30, r0 - BNEZ r0, .Lno_reset_pid /* CLONE_VM is set */ - moveli TREG_SYSCALL_NR_NAME, __NR_getpid - swint1 - ADDLI_PTR r2, tp, PID_OFFSET - { - ST4 r2, r0 - ADDLI_PTR r2, tp, TID_OFFSET - } - ST4 r2, r0 -.Lno_reset_pid: { /* Invoke user function with specified argument. */ move r0, r31 diff --git a/sysdeps/unix/sysv/linux/tile/vfork.S b/sysdeps/unix/sysv/linux/tile/vfork.S index d8c5ce3e24..2272777187 100644 --- a/sysdeps/unix/sysv/linux/tile/vfork.S +++ b/sysdeps/unix/sysv/linux/tile/vfork.S @@ -29,18 +29,6 @@ .text ENTRY (__vfork) - { - addli r11, tp, PID_OFFSET /* Point at PID. */ - movei r13, 1 - } - { - LD4U r12, r11 /* Load the saved PID. */ - shli r13, r13, 31 /* Build 0x80000000. */ - } - sub r12, zero, r12 /* Negate it. */ - CMOVEQZ r12, r12, r13 /* Replace zero pids. */ - ST4 r11, r12 /* Store the temporary PID. */ - { moveli r0, CLONE_VFORK | CLONE_VM | SIGCHLD move r1, zero @@ -52,22 +40,6 @@ ENTRY (__vfork) moveli TREG_SYSCALL_NR_NAME, __NR_clone swint1 - BEQZ r0, 1f /* If we are the parent... */ - { - addli r11, tp, PID_OFFSET /* Point at PID. */ - movei r13, 1 - } - { - LD4U r12, r11 /* Load the saved PID. */ - shli r13, r13, 31 /* Build 0x80000000. */ - } - { - CMPEQ r13, r12, r12 /* Test for that value. */ - sub r12, zero, r12 /* Re-negate it. */ - } - CMOVNEZ r12, r13, zero /* Replace zero pids. */ - ST4 r11, r12 /* Restore the PID. */ -1: BNEZ r1, 0f jrp lr PSEUDO_END (__vfork) diff --git a/sysdeps/unix/sysv/linux/tst-clone2.c b/sysdeps/unix/sysv/linux/tst-clone2.c index 68a7e6d6e2..1472311947 100644 --- a/sysdeps/unix/sysv/linux/tst-clone2.c +++ b/sysdeps/unix/sysv/linux/tst-clone2.c @@ -28,8 +28,11 @@ #include #include #include +#include -#include /* for THREAD_* macros. */ +#include /* For _STACK_GROWS_{UP,DOWN}. */ + +#include static int sig; static int pipefd[2]; @@ -39,39 +42,35 @@ f (void *a) { close (pipefd[0]); - pid_t pid = THREAD_GETMEM (THREAD_SELF, pid); - pid_t tid = THREAD_GETMEM (THREAD_SELF, tid); + pid_t ppid = getppid (); + pid_t pid = getpid (); + pid_t tid = syscall (__NR_gettid); - while (write (pipefd[1], &pid, sizeof pid) < 0) - continue; - while (write (pipefd[1], &tid, sizeof tid) < 0) - continue; + if (write (pipefd[1], &ppid, sizeof ppid) != sizeof (ppid)) + FAIL_EXIT1 ("write ppid failed\n"); + if (write (pipefd[1], &pid, sizeof pid) != sizeof (pid)) + FAIL_EXIT1 ("write pid failed\n"); + if (write (pipefd[1], &tid, sizeof tid) != sizeof (tid)) + FAIL_EXIT1 ("write tid failed\n"); return 0; } static int -clone_test (int clone_flags) +do_test (void) { sig = SIGRTMIN; sigset_t ss; sigemptyset (&ss); sigaddset (&ss, sig); if (sigprocmask (SIG_BLOCK, &ss, NULL) != 0) - { - printf ("sigprocmask failed: %m\n"); - return 1; - } + FAIL_EXIT1 ("sigprocmask failed: %m"); if (pipe2 (pipefd, O_CLOEXEC)) - { - printf ("sigprocmask failed: %m\n"); - return 1; - } - - pid_t ppid = getpid (); + FAIL_EXIT1 ("pipe failed: %m"); + int clone_flags = 0; #ifdef __ia64__ extern int __clone2 (int (*__fn) (void *__arg), void *__child_stack_base, size_t __child_stack_size, int __flags, @@ -88,61 +87,47 @@ clone_test (int clone_flags) #error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP" #endif #endif + close (pipefd[1]); if (p == -1) + FAIL_EXIT1("clone failed: %m"); + + pid_t ppid, pid, tid; + if (read (pipefd[0], &ppid, sizeof pid) != sizeof pid) { - printf ("clone failed: %m\n"); - return 1; + kill (p, SIGKILL); + FAIL_EXIT1 ("read ppid failed: %m"); } - - pid_t pid, tid; if (read (pipefd[0], &pid, sizeof pid) != sizeof pid) { - printf ("read pid failed: %m\n"); kill (p, SIGKILL); - return 1; + FAIL_EXIT1 ("read pid failed: %m"); } if (read (pipefd[0], &tid, sizeof tid) != sizeof tid) { - printf ("read pid failed: %m\n"); kill (p, SIGKILL); - return 1; + FAIL_EXIT1 ("read tid failed: %m"); } close (pipefd[0]); int ret = 0; - /* For CLONE_VM glibc clone implementation does not change the pthread - pid/tid field. */ - if ((clone_flags & CLONE_VM) == CLONE_VM) - { - if ((ppid != pid) || (ppid != tid)) - { - printf ("parent pid (%i) != received pid/tid (%i/%i)\n", - (int)ppid, (int)pid, (int)tid); - ret = 1; - } - } - /* For any other flag clone updates the new pthread pid and tid with - the clone return value. */ - else - { - if ((p != pid) || (p != tid)) - { - printf ("child pid (%i) != received pid/tid (%i/%i)\n", - (int)p, (int)pid, (int)tid); - ret = 1; - } - } + pid_t own_pid = getpid (); + pid_t own_tid = syscall (__NR_gettid); + + /* Some sanity checks for clone syscall: returned ppid should be current + pid and both returned tid/pid should be different from current one. */ + if ((ppid != own_pid) || (pid == own_pid) || (tid == own_tid)) + FAIL_RET ("ppid=%i pid=%i tid=%i | own_pid=%i own_tid=%i", + (int)ppid, (int)pid, (int)tid, (int)own_pid, (int)own_tid); int e; if (waitpid (p, &e, __WCLONE) != p) { - puts ("waitpid failed"); kill (p, SIGKILL); - return 1; + FAIL_EXIT1 ("waitpid failed"); } if (!WIFEXITED (e)) { @@ -150,29 +135,12 @@ clone_test (int clone_flags) printf ("died from signal %s\n", strsignal (WTERMSIG (e))); else puts ("did not terminate correctly"); - return 1; + exit (EXIT_FAILURE); } if (WEXITSTATUS (e) != 0) - { - printf ("exit code %d\n", WEXITSTATUS (e)); - return 1; - } + FAIL_EXIT1 ("exit code %d", WEXITSTATUS (e)); return ret; } -int -do_test (void) -{ - /* First, check that the clone implementation, without any flag, updates - the struct pthread to contain the new PID and TID. */ - int ret = clone_test (0); - /* Second, check that with CLONE_VM the struct pthread PID and TID fields - remain unmodified after the clone. Any modifications would cause problem - for the parent as described in bug 19957. */ - ret += clone_test (CLONE_VM); - return ret; -} - -#define TEST_FUNCTION do_test () -#include "../test-skeleton.c" +#include diff --git a/sysdeps/unix/sysv/linux/wordsize-64/globfree64.c b/sysdeps/unix/sysv/linux/wordsize-64/globfree64.c new file mode 100644 index 0000000000..af035e1514 --- /dev/null +++ b/sysdeps/unix/sysv/linux/wordsize-64/globfree64.c @@ -0,0 +1,2 @@ +/* This file is here so sysdeps/gnu/glob64.c doesn't take precedence. */ +#include diff --git a/sysdeps/unix/sysv/linux/x86_64/clone.S b/sysdeps/unix/sysv/linux/x86_64/clone.S index 66f4b11490..5629aed395 100644 --- a/sysdeps/unix/sysv/linux/x86_64/clone.S +++ b/sysdeps/unix/sysv/linux/x86_64/clone.S @@ -91,14 +91,6 @@ L(thread_start): the outermost frame obviously. */ xorl %ebp, %ebp - andq $CLONE_VM, %rdi - jne 1f - movl $SYS_ify(getpid), %eax - syscall - movl %eax, %fs:PID - movl %eax, %fs:TID -1: - /* Set up arguments for the function call. */ popq %rax /* Function to call. */ popq %rdi /* Argument. */ diff --git a/sysdeps/unix/sysv/linux/x86_64/vfork.S b/sysdeps/unix/sysv/linux/x86_64/vfork.S index 8332ade9fb..cdd2dea32a 100644 --- a/sysdeps/unix/sysv/linux/x86_64/vfork.S +++ b/sysdeps/unix/sysv/linux/x86_64/vfork.S @@ -34,16 +34,6 @@ ENTRY (__vfork) cfi_adjust_cfa_offset(-8) cfi_register(%rip, %rdi) - /* Save the TCB-cached PID away in %esi, and then negate the TCB - field. But if it's zero, set it to 0x80000000 instead. See - raise.c for the logic that relies on this value. */ - movl %fs:PID, %esi - movl $0x80000000, %ecx - movl %esi, %edx - negl %edx - cmove %ecx, %edx - movl %edx, %fs:PID - /* Stuff the syscall number in RAX and enter into the kernel. */ movl $SYS_ify (vfork), %eax syscall @@ -52,14 +42,6 @@ ENTRY (__vfork) pushq %rdi cfi_adjust_cfa_offset(8) - /* Restore the original value of the TCB cache of the PID, if we're - the parent. But in the child (syscall return value equals zero), - leave things as they are. */ - testq %rax, %rax - je 1f - movl %esi, %fs:PID -1: - cmpl $-4095, %eax jae SYSCALL_ERROR_LABEL /* Branch forward if it failed. */ diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/globfree.c b/sysdeps/unix/sysv/linux/x86_64/x32/globfree.c new file mode 100644 index 0000000000..b76a761c17 --- /dev/null +++ b/sysdeps/unix/sysv/linux/x86_64/x32/globfree.c @@ -0,0 +1 @@ +#include diff --git a/sysdeps/wordsize-64/glob.c b/sysdeps/wordsize-64/glob.c index 082faf1c70..954e8d37e2 100644 --- a/sysdeps/wordsize-64/glob.c +++ b/sysdeps/wordsize-64/glob.c @@ -4,5 +4,3 @@ #undef glob64 #undef globfree64 weak_alias (glob, glob64) -weak_alias (globfree, globfree64) -libc_hidden_ver (globfree, globfree64) diff --git a/sysdeps/wordsize-64/globfree.c b/sysdeps/wordsize-64/globfree.c new file mode 100644 index 0000000000..ec8c35b489 --- /dev/null +++ b/sysdeps/wordsize-64/globfree.c @@ -0,0 +1,5 @@ +#define globfree64 __no_globfree64_decl +#include +#undef globfree64 +weak_alias (globfree, globfree64) +libc_hidden_ver (globfree, globfree64) diff --git a/sysdeps/wordsize-64/globfree64.c b/sysdeps/wordsize-64/globfree64.c new file mode 100644 index 0000000000..a0f57ff4b3 --- /dev/null +++ b/sysdeps/wordsize-64/globfree64.c @@ -0,0 +1 @@ +/* globfree64 is in globfree.c */ diff --git a/sysdeps/x86/cpu-features-offsets.sym b/sysdeps/x86/cpu-features-offsets.sym index f6739fae81..33dd094e37 100644 --- a/sysdeps/x86/cpu-features-offsets.sym +++ b/sysdeps/x86/cpu-features-offsets.sym @@ -15,6 +15,7 @@ CPUID_ECX_OFFSET offsetof (struct cpuid_registers, ecx) CPUID_EDX_OFFSET offsetof (struct cpuid_registers, edx) FAMILY_OFFSET offsetof (struct cpu_features, family) MODEL_OFFSET offsetof (struct cpu_features, model) +XSAVE_STATE_SIZE_OFFSET offsetof (struct cpu_features, xsave_state_size) FEATURE_OFFSET offsetof (struct cpu_features, feature) FEATURE_SIZE sizeof (unsigned int) diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c index 9ce4b495a5..9eca98817d 100644 --- a/sysdeps/x86/cpu-features.c +++ b/sysdeps/x86/cpu-features.c @@ -18,6 +18,7 @@ #include #include +#include static void get_common_indeces (struct cpu_features *cpu_features, @@ -88,6 +89,71 @@ get_common_indeces (struct cpu_features *cpu_features, cpu_features->feature[index_arch_FMA_Usable] |= bit_arch_FMA_Usable; } + + /* For _dl_runtime_resolve, set xsave_state_size to xsave area + size + integer register save size and align it to 64 bytes. */ + if (cpu_features->max_cpuid >= 0xd) + { + unsigned int eax, ebx, ecx, edx; + + __cpuid_count (0xd, 0, eax, ebx, ecx, edx); + if (ebx != 0) + { + cpu_features->xsave_state_size + = ALIGN_UP (ebx + STATE_SAVE_OFFSET, 64); + + __cpuid_count (0xd, 1, eax, ebx, ecx, edx); + + /* Check if XSAVEC is available. */ + if ((eax & (1 << 1)) != 0) + { + unsigned int xstate_comp_offsets[32]; + unsigned int xstate_comp_sizes[32]; + unsigned int i; + + xstate_comp_offsets[0] = 0; + xstate_comp_offsets[1] = 160; + xstate_comp_offsets[2] = 576; + xstate_comp_sizes[0] = 160; + xstate_comp_sizes[1] = 256; + + for (i = 2; i < 32; i++) + { + if ((STATE_SAVE_MASK & (1 << i)) != 0) + { + __cpuid_count (0xd, i, eax, ebx, ecx, edx); + xstate_comp_sizes[i] = eax; + } + else + { + ecx = 0; + xstate_comp_sizes[i] = 0; + } + + if (i > 2) + { + xstate_comp_offsets[i] + = (xstate_comp_offsets[i - 1] + + xstate_comp_sizes[i -1]); + if ((ecx & (1 << 1)) != 0) + xstate_comp_offsets[i] + = ALIGN_UP (xstate_comp_offsets[i], 64); + } + } + + /* Use XSAVEC. */ + unsigned int size + = xstate_comp_offsets[31] + xstate_comp_sizes[31]; + if (size) + { + cpu_features->xsave_state_size + = ALIGN_UP (size + STATE_SAVE_OFFSET, 64); + cpu_features->feature[index_arch_XSAVEC_Usable] + |= bit_arch_XSAVEC_Usable; + } + } + } + } } } @@ -133,8 +199,6 @@ init_cpu_features (struct cpu_features *cpu_features) case 0x57: /* Knights Landing. Enable Silvermont optimizations. */ - cpu_features->feature[index_arch_Prefer_No_VZEROUPPER] - |= bit_arch_Prefer_No_VZEROUPPER; case 0x5c: case 0x5f: @@ -205,6 +269,16 @@ init_cpu_features (struct cpu_features *cpu_features) if (CPU_FEATURES_ARCH_P (cpu_features, AVX2_Usable)) cpu_features->feature[index_arch_AVX_Fast_Unaligned_Load] |= bit_arch_AVX_Fast_Unaligned_Load; + + /* Since AVX512ER is unique to Xeon Phi, set Prefer_No_VZEROUPPER + if AVX512ER is available. Don't use AVX512 to avoid lower CPU + frequency if AVX512ER isn't available. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX512ER)) + cpu_features->feature[index_arch_Prefer_No_VZEROUPPER] + |= bit_arch_Prefer_No_VZEROUPPER; + else + cpu_features->feature[index_arch_Prefer_No_AVX512] + |= bit_arch_Prefer_No_AVX512; } /* This spells out "AuthenticAMD". */ else if (ebx == 0x68747541 && ecx == 0x444d4163 && edx == 0x69746e65) diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h index 97ffe765f4..507a141414 100644 --- a/sysdeps/x86/cpu-features.h +++ b/sysdeps/x86/cpu-features.h @@ -37,6 +37,8 @@ #define bit_arch_Prefer_No_VZEROUPPER (1 << 17) #define bit_arch_Fast_Unaligned_Copy (1 << 18) #define bit_arch_Prefer_ERMS (1 << 19) +#define bit_arch_Prefer_No_AVX512 (1 << 20) +#define bit_arch_XSAVEC_Usable (1 << 21) /* CPUID Feature flags. */ @@ -60,6 +62,11 @@ #define bit_cpu_AVX2 (1 << 5) #define bit_cpu_AVX512F (1 << 16) #define bit_cpu_AVX512DQ (1 << 17) +#define bit_cpu_AVX512PF (1 << 26) +#define bit_cpu_AVX512ER (1 << 27) +#define bit_cpu_AVX512CD (1 << 28) +#define bit_cpu_AVX512BW (1 << 30) +#define bit_cpu_AVX512VL (1u << 31) /* XCR0 Feature flags. */ #define bit_XMM_state (1 << 1) @@ -74,6 +81,15 @@ /* The current maximum size of the feature integer bit array. */ #define FEATURE_INDEX_MAX 1 +/* Offset for fxsave/xsave area used by _dl_runtime_resolve. Also need + space to preserve RCX, RDX, RSI, RDI, R8, R9 and RAX. It must be + aligned to 16 bytes for fxsave and 64 bytes for xsave. */ +#define STATE_SAVE_OFFSET (8 * 7 + 8) + +/* Save SSE, AVX, AVX512, mask and bound registers. */ +#define STATE_SAVE_MASK \ + ((1 << 1) | (1 << 2) | (1 << 3) | (1 << 5) | (1 << 6) | (1 << 7)) + #ifdef __ASSEMBLER__ # include @@ -107,6 +123,9 @@ # define index_arch_Prefer_No_VZEROUPPER FEATURE_INDEX_1*FEATURE_SIZE # define index_arch_Fast_Unaligned_Copy FEATURE_INDEX_1*FEATURE_SIZE # define index_arch_Prefer_ERMS FEATURE_INDEX_1*FEATURE_SIZE +# define index_arch_Use_dl_runtime_resolve_opt FEATURE_INDEX_1*FEATURE_SIZE +# define index_arch_Use_dl_runtime_resolve_slow FEATURE_INDEX_1*FEATURE_SIZE +# define index_arch_Prefer_No_AVX512 FEATURE_INDEX_1*FEATURE_SIZE # if defined (_LIBC) && !IS_IN (nonlib) @@ -195,6 +214,12 @@ struct cpu_features } cpuid[COMMON_CPUID_INDEX_MAX]; unsigned int family; unsigned int model; + /* The type must be unsigned long int so that we use + + sub xsave_state_size_offset(%rip) %RSP_LP + + in _dl_runtime_resolve. */ + unsigned long int xsave_state_size; unsigned int feature[FEATURE_INDEX_MAX]; }; @@ -232,6 +257,11 @@ extern const struct cpu_features *__get_cpu_features (void) # define index_cpu_AVX2 COMMON_CPUID_INDEX_7 # define index_cpu_AVX512F COMMON_CPUID_INDEX_7 # define index_cpu_AVX512DQ COMMON_CPUID_INDEX_7 +# define index_cpu_AVX512PF COMMON_CPUID_INDEX_7 +# define index_cpu_AVX512ER COMMON_CPUID_INDEX_7 +# define index_cpu_AVX512CD COMMON_CPUID_INDEX_7 +# define index_cpu_AVX512BW COMMON_CPUID_INDEX_7 +# define index_cpu_AVX512VL COMMON_CPUID_INDEX_7 # define index_cpu_ERMS COMMON_CPUID_INDEX_7 # define index_cpu_RTM COMMON_CPUID_INDEX_7 # define index_cpu_FMA COMMON_CPUID_INDEX_1 @@ -250,6 +280,11 @@ extern const struct cpu_features *__get_cpu_features (void) # define reg_AVX2 ebx # define reg_AVX512F ebx # define reg_AVX512DQ ebx +# define reg_AVX512PF ebx +# define reg_AVX512ER ebx +# define reg_AVX512CD ebx +# define reg_AVX512BW ebx +# define reg_AVX512VL ebx # define reg_ERMS ebx # define reg_RTM ebx # define reg_FMA ecx @@ -277,6 +312,8 @@ extern const struct cpu_features *__get_cpu_features (void) # define index_arch_Prefer_No_VZEROUPPER FEATURE_INDEX_1 # define index_arch_Fast_Unaligned_Copy FEATURE_INDEX_1 # define index_arch_Prefer_ERMS FEATURE_INDEX_1 +# define index_arch_Prefer_No_AVX512 FEATURE_INDEX_1 +# define index_arch_XSAVEC_Usable FEATURE_INDEX_1 #endif /* !__ASSEMBLER__ */ diff --git a/sysdeps/x86_64/Makefile b/sysdeps/x86_64/Makefile index 6d99284cd0..cc990a9685 100644 --- a/sysdeps/x86_64/Makefile +++ b/sysdeps/x86_64/Makefile @@ -27,7 +27,7 @@ ifeq ($(subdir),elf) CFLAGS-.os += $(if $(filter $(@F),$(patsubst %,%.os,$(all-rtld-routines))),\ -mno-mmx) -sysdep-dl-routines += tlsdesc dl-tlsdesc +sysdep-dl-routines += tlsdesc dl-tlsdesc tls_get_addr tests += ifuncmain8 modules-names += ifuncmod8 @@ -49,9 +49,12 @@ extra-test-objs += tst-quadmod1pie.o tst-quadmod2pie.o $(objpfx)tst-quad1pie: $(objpfx)tst-quadmod1pie.o $(objpfx)tst-quad2pie: $(objpfx)tst-quadmod2pie.o -tests += tst-audit3 tst-audit4 tst-audit5 tst-audit6 tst-audit7 tst-audit10 -test-extras += tst-audit4-aux tst-audit10-aux -extra-test-objs += tst-audit4-aux.o tst-audit10-aux.o +tests += tst-audit3 tst-audit4 tst-audit5 tst-audit6 tst-audit7 \ + tst-audit10 tst-sse tst-avx tst-avx512 +test-extras += tst-audit4-aux tst-audit10-aux \ + tst-avx-aux tst-avx512-aux +extra-test-objs += tst-audit4-aux.o tst-audit10-aux.o \ + tst-avx-aux.o tst-avx512-aux.o tests += tst-split-dynreloc LDFLAGS-tst-split-dynreloc = -Wl,-T,$(..)sysdeps/x86_64/tst-split-dynreloc.lds @@ -62,7 +65,8 @@ modules-names += tst-auditmod3a tst-auditmod3b \ tst-auditmod5a tst-auditmod5b \ tst-auditmod6a tst-auditmod6b tst-auditmod6c \ tst-auditmod7a tst-auditmod7b \ - tst-auditmod10a tst-auditmod10b + tst-auditmod10a tst-auditmod10b \ + tst-ssemod tst-avxmod tst-avx512mod $(objpfx)tst-audit3: $(objpfx)tst-auditmod3a.so $(objpfx)tst-audit3.out: $(objpfx)tst-auditmod3b.so @@ -89,6 +93,10 @@ $(objpfx)tst-audit10: $(objpfx)tst-audit10-aux.o $(objpfx)tst-auditmod10a.so $(objpfx)tst-audit10.out: $(objpfx)tst-auditmod10b.so tst-audit10-ENV = LD_AUDIT=$(objpfx)tst-auditmod10b.so +$(objpfx)tst-sse: $(objpfx)tst-ssemod.so +$(objpfx)tst-avx: $(objpfx)tst-avx-aux.o $(objpfx)tst-avxmod.so +$(objpfx)tst-avx512: $(objpfx)tst-avx512-aux.o $(objpfx)tst-avx512mod.so + AVX-CFLAGS=-mavx -mno-vzeroupper CFLAGS-tst-audit4-aux.c += $(AVX-CFLAGS) CFLAGS-tst-auditmod4a.c += $(AVX-CFLAGS) @@ -96,14 +104,18 @@ CFLAGS-tst-auditmod4b.c += $(AVX-CFLAGS) CFLAGS-tst-auditmod6b.c += $(AVX-CFLAGS) CFLAGS-tst-auditmod6c.c += $(AVX-CFLAGS) CFLAGS-tst-auditmod7b.c += $(AVX-CFLAGS) +CFLAGS-tst-avx-aux.c += $(AVX-CFLAGS) +CFLAGS-tst-avxmod.c += $(AVX-CFLAGS) ifeq (yes,$(config-cflags-avx512)) AVX512-CFLAGS = -mavx512f CFLAGS-tst-audit10-aux.c += $(AVX512-CFLAGS) CFLAGS-tst-auditmod10a.c += $(AVX512-CFLAGS) CFLAGS-tst-auditmod10b.c += $(AVX512-CFLAGS) +CFLAGS-tst-avx512-aux.c += $(AVX512-CFLAGS) +CFLAGS-tst-avx512mod.c += $(AVX512-CFLAGS) endif endif ifeq ($(subdir),csu) -gen-as-const-headers += tlsdesc.sym +gen-as-const-headers += tlsdesc.sym rtld-offsets.sym endif diff --git a/sysdeps/x86_64/dl-machine.h b/sysdeps/x86_64/dl-machine.h index ed0c1a8efd..8355432dfc 100644 --- a/sysdeps/x86_64/dl-machine.h +++ b/sysdeps/x86_64/dl-machine.h @@ -66,9 +66,9 @@ static inline int __attribute__ ((unused, always_inline)) elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) { Elf64_Addr *got; - extern void _dl_runtime_resolve_sse (ElfW(Word)) attribute_hidden; - extern void _dl_runtime_resolve_avx (ElfW(Word)) attribute_hidden; - extern void _dl_runtime_resolve_avx512 (ElfW(Word)) attribute_hidden; + extern void _dl_runtime_resolve_fxsave (ElfW(Word)) attribute_hidden; + extern void _dl_runtime_resolve_xsave (ElfW(Word)) attribute_hidden; + extern void _dl_runtime_resolve_xsavec (ElfW(Word)) attribute_hidden; extern void _dl_runtime_profile_sse (ElfW(Word)) attribute_hidden; extern void _dl_runtime_profile_avx (ElfW(Word)) attribute_hidden; extern void _dl_runtime_profile_avx512 (ElfW(Word)) attribute_hidden; @@ -117,12 +117,14 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) /* This function will get called to fix up the GOT entry indicated by the offset on the stack, and then jump to the resolved address. */ - if (HAS_ARCH_FEATURE (AVX512F_Usable)) - *(ElfW(Addr) *) (got + 2) = (ElfW(Addr)) &_dl_runtime_resolve_avx512; - else if (HAS_ARCH_FEATURE (AVX_Usable)) - *(ElfW(Addr) *) (got + 2) = (ElfW(Addr)) &_dl_runtime_resolve_avx; + if (GLRO(dl_x86_cpu_features).xsave_state_size != 0) + *(ElfW(Addr) *) (got + 2) + = (HAS_ARCH_FEATURE (XSAVEC_Usable) + ? (ElfW(Addr)) &_dl_runtime_resolve_xsavec + : (ElfW(Addr)) &_dl_runtime_resolve_xsave); else - *(ElfW(Addr) *) (got + 2) = (ElfW(Addr)) &_dl_runtime_resolve_sse; + *(ElfW(Addr) *) (got + 2) + = (ElfW(Addr)) &_dl_runtime_resolve_fxsave; } } diff --git a/sysdeps/x86_64/dl-tls.c b/sysdeps/x86_64/dl-tls.c new file mode 100644 index 0000000000..3584805c8e --- /dev/null +++ b/sysdeps/x86_64/dl-tls.c @@ -0,0 +1,53 @@ +/* Thread-local storage handling in the ELF dynamic linker. x86-64 version. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifdef SHARED +/* Work around GCC PR58066, due to which __tls_get_addr may be called + with an unaligned stack. The compat implementation is in + tls_get_addr-compat.S. */ + +# include + +/* Define __tls_get_addr within elf/dl-tls.c under a different + name. */ +extern __typeof__ (__tls_get_addr) ___tls_get_addr; + +# define __tls_get_addr ___tls_get_addr +# include +# undef __tls_get_addr + +hidden_ver (___tls_get_addr, __tls_get_addr) + +/* Only handle slow paths for __tls_get_addr. */ +attribute_hidden +void * +__tls_get_addr_slow (GET_ADDR_ARGS) +{ + dtv_t *dtv = THREAD_DTV (); + + if (__glibc_unlikely (dtv[0].counter != GL(dl_tls_generation))) + return update_get_addr (GET_ADDR_PARAM); + + return tls_get_addr_tail (GET_ADDR_PARAM, dtv, NULL); +} +#else + +/* No compatibility symbol needed. */ +# include + +#endif diff --git a/sysdeps/x86_64/dl-tls.h b/sysdeps/x86_64/dl-tls.h index cf6c107f54..fa5bf6cd93 100644 --- a/sysdeps/x86_64/dl-tls.h +++ b/sysdeps/x86_64/dl-tls.h @@ -16,6 +16,9 @@ License along with the GNU C Library; if not, see . */ +#ifndef _X86_64_DL_TLS_H +#define _X86_64_DL_TLS_H + #include /* Type used for the representation of TLS information in the GOT. */ @@ -27,3 +30,5 @@ typedef struct dl_tls_index extern void *__tls_get_addr (tls_index *ti); + +#endif /* _X86_64_DL_TLS_H */ diff --git a/sysdeps/x86_64/dl-trampoline.S b/sysdeps/x86_64/dl-trampoline.S index 12f1a5cf84..b4cda0f535 100644 --- a/sysdeps/x86_64/dl-trampoline.S +++ b/sysdeps/x86_64/dl-trampoline.S @@ -18,6 +18,7 @@ #include #include +#include #include #ifndef DL_STACK_ALIGNMENT @@ -33,41 +34,24 @@ # define DL_STACK_ALIGNMENT 8 #endif -#ifndef DL_RUNTIME_UNALIGNED_VEC_SIZE -/* The maximum size in bytes of unaligned vector load and store in the - dynamic linker. Since SSE optimized memory/string functions with - aligned SSE register load and store are used in the dynamic linker, - we must set this to 8 so that _dl_runtime_resolve_sse will align the - stack before calling _dl_fixup. */ -# define DL_RUNTIME_UNALIGNED_VEC_SIZE 8 -#endif - -/* True if _dl_runtime_resolve should align stack to VEC_SIZE bytes. */ +/* True if _dl_runtime_resolve should align stack for STATE_SAVE or align + stack to 16 bytes before calling _dl_fixup. */ #define DL_RUNTIME_RESOLVE_REALIGN_STACK \ - (VEC_SIZE > DL_STACK_ALIGNMENT \ - && VEC_SIZE > DL_RUNTIME_UNALIGNED_VEC_SIZE) - -/* Align vector register save area to 16 bytes. */ -#define REGISTER_SAVE_VEC_OFF 0 + (STATE_SAVE_ALIGNMENT > DL_STACK_ALIGNMENT \ + || 16 > DL_STACK_ALIGNMENT) /* Area on stack to save and restore registers used for parameter passing when calling _dl_fixup. */ #ifdef __ILP32__ -# define REGISTER_SAVE_RAX (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 8) # define PRESERVE_BND_REGS_PREFIX #else -/* Align bound register save area to 16 bytes. */ -# define REGISTER_SAVE_BND0 (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 8) -# define REGISTER_SAVE_BND1 (REGISTER_SAVE_BND0 + 16) -# define REGISTER_SAVE_BND2 (REGISTER_SAVE_BND1 + 16) -# define REGISTER_SAVE_BND3 (REGISTER_SAVE_BND2 + 16) -# define REGISTER_SAVE_RAX (REGISTER_SAVE_BND3 + 16) # ifdef HAVE_MPX_SUPPORT # define PRESERVE_BND_REGS_PREFIX bnd # else # define PRESERVE_BND_REGS_PREFIX .byte 0xf2 # endif #endif +#define REGISTER_SAVE_RAX 0 #define REGISTER_SAVE_RCX (REGISTER_SAVE_RAX + 8) #define REGISTER_SAVE_RDX (REGISTER_SAVE_RCX + 8) #define REGISTER_SAVE_RSI (REGISTER_SAVE_RDX + 8) @@ -79,50 +63,56 @@ #define VEC_SIZE 64 #define VMOVA vmovdqa64 -#if DL_RUNTIME_RESOLVE_REALIGN_STACK || VEC_SIZE <= DL_STACK_ALIGNMENT -# define VMOV vmovdqa64 -#else -# define VMOV vmovdqu64 -#endif #define VEC(i) zmm##i -#define _dl_runtime_resolve _dl_runtime_resolve_avx512 #define _dl_runtime_profile _dl_runtime_profile_avx512 #include "dl-trampoline.h" -#undef _dl_runtime_resolve #undef _dl_runtime_profile #undef VEC -#undef VMOV #undef VMOVA #undef VEC_SIZE #define VEC_SIZE 32 #define VMOVA vmovdqa -#if DL_RUNTIME_RESOLVE_REALIGN_STACK || VEC_SIZE <= DL_STACK_ALIGNMENT -# define VMOV vmovdqa -#else -# define VMOV vmovdqu -#endif #define VEC(i) ymm##i -#define _dl_runtime_resolve _dl_runtime_resolve_avx #define _dl_runtime_profile _dl_runtime_profile_avx #include "dl-trampoline.h" -#undef _dl_runtime_resolve #undef _dl_runtime_profile #undef VEC -#undef VMOV #undef VMOVA #undef VEC_SIZE /* movaps/movups is 1-byte shorter. */ #define VEC_SIZE 16 #define VMOVA movaps -#if DL_RUNTIME_RESOLVE_REALIGN_STACK || VEC_SIZE <= DL_STACK_ALIGNMENT -# define VMOV movaps -#else -# define VMOV movups -#endif #define VEC(i) xmm##i -#define _dl_runtime_resolve _dl_runtime_resolve_sse #define _dl_runtime_profile _dl_runtime_profile_sse #undef RESTORE_AVX #include "dl-trampoline.h" +#undef _dl_runtime_profile +#undef VEC +#undef VMOVA +#undef VEC_SIZE + +#define USE_FXSAVE +#define STATE_SAVE_ALIGNMENT 16 +#define _dl_runtime_resolve _dl_runtime_resolve_fxsave +#include "dl-trampoline.h" +#undef _dl_runtime_resolve +#undef USE_FXSAVE +#undef STATE_SAVE_ALIGNMENT + +#define USE_XSAVE +#define STATE_SAVE_ALIGNMENT 64 +#define _dl_runtime_resolve _dl_runtime_resolve_xsave +#include "dl-trampoline.h" +#undef _dl_runtime_resolve +#undef USE_XSAVE +#undef STATE_SAVE_ALIGNMENT + +#define USE_XSAVEC +#define STATE_SAVE_ALIGNMENT 64 +#define _dl_runtime_resolve _dl_runtime_resolve_xsavec +#include "dl-trampoline.h" +#undef _dl_runtime_resolve +#undef USE_XSAVEC +#undef STATE_SAVE_ALIGNMENT diff --git a/sysdeps/x86_64/dl-trampoline.h b/sysdeps/x86_64/dl-trampoline.h index b90836ab13..b9c2f1796f 100644 --- a/sysdeps/x86_64/dl-trampoline.h +++ b/sysdeps/x86_64/dl-trampoline.h @@ -16,40 +16,47 @@ License along with the GNU C Library; if not, see . */ -#undef REGISTER_SAVE_AREA_RAW -#ifdef __ILP32__ -/* X32 saves RCX, RDX, RSI, RDI, R8 and R9 plus RAX as well as VEC0 to - VEC7. */ -# define REGISTER_SAVE_AREA_RAW (8 * 7 + VEC_SIZE * 8) -#else -/* X86-64 saves RCX, RDX, RSI, RDI, R8 and R9 plus RAX as well as - BND0, BND1, BND2, BND3 and VEC0 to VEC7. */ -# define REGISTER_SAVE_AREA_RAW (8 * 7 + 16 * 4 + VEC_SIZE * 8) -#endif + .text +#ifdef _dl_runtime_resolve -#undef REGISTER_SAVE_AREA -#undef LOCAL_STORAGE_AREA -#undef BASE -#if DL_RUNTIME_RESOLVE_REALIGN_STACK -# define REGISTER_SAVE_AREA (REGISTER_SAVE_AREA_RAW + 8) -/* Local stack area before jumping to function address: RBX. */ -# define LOCAL_STORAGE_AREA 8 -# define BASE rbx -# if (REGISTER_SAVE_AREA % VEC_SIZE) != 0 -# error REGISTER_SAVE_AREA must be multples of VEC_SIZE +# undef REGISTER_SAVE_AREA +# undef LOCAL_STORAGE_AREA +# undef BASE + +# if (STATE_SAVE_ALIGNMENT % 16) != 0 +# error STATE_SAVE_ALIGNMENT must be multples of 16 # endif -#else -# define REGISTER_SAVE_AREA REGISTER_SAVE_AREA_RAW + +# if (STATE_SAVE_OFFSET % STATE_SAVE_ALIGNMENT) != 0 +# error STATE_SAVE_OFFSET must be multples of STATE_SAVE_ALIGNMENT +# endif + +# if DL_RUNTIME_RESOLVE_REALIGN_STACK +/* Local stack area before jumping to function address: RBX. */ +# define LOCAL_STORAGE_AREA 8 +# define BASE rbx +# ifdef USE_FXSAVE +/* Use fxsave to save XMM registers. */ +# define REGISTER_SAVE_AREA (512 + STATE_SAVE_OFFSET) +# if (REGISTER_SAVE_AREA % 16) != 0 +# error REGISTER_SAVE_AREA must be multples of 16 +# endif +# endif +# else +# ifndef USE_FXSAVE +# error USE_FXSAVE must be defined +# endif +/* Use fxsave to save XMM registers. */ +# define REGISTER_SAVE_AREA (512 + STATE_SAVE_OFFSET + 8) /* Local stack area before jumping to function address: All saved registers. */ -# define LOCAL_STORAGE_AREA REGISTER_SAVE_AREA -# define BASE rsp -# if (REGISTER_SAVE_AREA % 16) != 8 -# error REGISTER_SAVE_AREA must be odd multples of 8 +# define LOCAL_STORAGE_AREA REGISTER_SAVE_AREA +# define BASE rsp +# if (REGISTER_SAVE_AREA % 16) != 8 +# error REGISTER_SAVE_AREA must be odd multples of 8 +# endif # endif -#endif - .text .globl _dl_runtime_resolve .hidden _dl_runtime_resolve .type _dl_runtime_resolve, @function @@ -57,19 +64,30 @@ cfi_startproc _dl_runtime_resolve: cfi_adjust_cfa_offset(16) # Incorporate PLT -#if DL_RUNTIME_RESOLVE_REALIGN_STACK -# if LOCAL_STORAGE_AREA != 8 -# error LOCAL_STORAGE_AREA must be 8 -# endif +# if DL_RUNTIME_RESOLVE_REALIGN_STACK +# if LOCAL_STORAGE_AREA != 8 +# error LOCAL_STORAGE_AREA must be 8 +# endif pushq %rbx # push subtracts stack by 8. cfi_adjust_cfa_offset(8) cfi_rel_offset(%rbx, 0) mov %RSP_LP, %RBX_LP cfi_def_cfa_register(%rbx) - and $-VEC_SIZE, %RSP_LP -#endif + and $-STATE_SAVE_ALIGNMENT, %RSP_LP +# endif +# ifdef REGISTER_SAVE_AREA sub $REGISTER_SAVE_AREA, %RSP_LP +# if !DL_RUNTIME_RESOLVE_REALIGN_STACK cfi_adjust_cfa_offset(REGISTER_SAVE_AREA) +# endif +# else + # Allocate stack space of the required size to save the state. +# if IS_IN (rtld) + sub _rtld_local_ro+RTLD_GLOBAL_RO_DL_X86_CPU_FEATURES_OFFSET+XSAVE_STATE_SIZE_OFFSET(%rip), %RSP_LP +# else + sub _dl_x86_cpu_features+XSAVE_STATE_SIZE_OFFSET(%rip), %RSP_LP +# endif +# endif # Preserve registers otherwise clobbered. movq %rax, REGISTER_SAVE_RAX(%rsp) movq %rcx, REGISTER_SAVE_RCX(%rsp) @@ -78,59 +96,42 @@ _dl_runtime_resolve: movq %rdi, REGISTER_SAVE_RDI(%rsp) movq %r8, REGISTER_SAVE_R8(%rsp) movq %r9, REGISTER_SAVE_R9(%rsp) - VMOV %VEC(0), (REGISTER_SAVE_VEC_OFF)(%rsp) - VMOV %VEC(1), (REGISTER_SAVE_VEC_OFF + VEC_SIZE)(%rsp) - VMOV %VEC(2), (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 2)(%rsp) - VMOV %VEC(3), (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 3)(%rsp) - VMOV %VEC(4), (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 4)(%rsp) - VMOV %VEC(5), (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 5)(%rsp) - VMOV %VEC(6), (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 6)(%rsp) - VMOV %VEC(7), (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 7)(%rsp) -#ifndef __ILP32__ - # We also have to preserve bound registers. These are nops if - # Intel MPX isn't available or disabled. -# ifdef HAVE_MPX_SUPPORT - bndmov %bnd0, REGISTER_SAVE_BND0(%rsp) - bndmov %bnd1, REGISTER_SAVE_BND1(%rsp) - bndmov %bnd2, REGISTER_SAVE_BND2(%rsp) - bndmov %bnd3, REGISTER_SAVE_BND3(%rsp) +# ifdef USE_FXSAVE + fxsave STATE_SAVE_OFFSET(%rsp) # else -# if REGISTER_SAVE_BND0 == 0 - .byte 0x66,0x0f,0x1b,0x04,0x24 + movl $STATE_SAVE_MASK, %eax + xorl %edx, %edx + # Clear the XSAVE Header. +# ifdef USE_XSAVE + movq %rdx, (STATE_SAVE_OFFSET + 512)(%rsp) + movq %rdx, (STATE_SAVE_OFFSET + 512 + 8)(%rsp) +# endif + movq %rdx, (STATE_SAVE_OFFSET + 512 + 8 * 2)(%rsp) + movq %rdx, (STATE_SAVE_OFFSET + 512 + 8 * 3)(%rsp) + movq %rdx, (STATE_SAVE_OFFSET + 512 + 8 * 4)(%rsp) + movq %rdx, (STATE_SAVE_OFFSET + 512 + 8 * 5)(%rsp) + movq %rdx, (STATE_SAVE_OFFSET + 512 + 8 * 6)(%rsp) + movq %rdx, (STATE_SAVE_OFFSET + 512 + 8 * 7)(%rsp) +# ifdef USE_XSAVE + xsave STATE_SAVE_OFFSET(%rsp) # else - .byte 0x66,0x0f,0x1b,0x44,0x24,REGISTER_SAVE_BND0 + xsavec STATE_SAVE_OFFSET(%rsp) # endif - .byte 0x66,0x0f,0x1b,0x4c,0x24,REGISTER_SAVE_BND1 - .byte 0x66,0x0f,0x1b,0x54,0x24,REGISTER_SAVE_BND2 - .byte 0x66,0x0f,0x1b,0x5c,0x24,REGISTER_SAVE_BND3 # endif -#endif # Copy args pushed by PLT in register. # %rdi: link_map, %rsi: reloc_index mov (LOCAL_STORAGE_AREA + 8)(%BASE), %RSI_LP mov LOCAL_STORAGE_AREA(%BASE), %RDI_LP call _dl_fixup # Call resolver. mov %RAX_LP, %R11_LP # Save return value -#ifndef __ILP32__ - # Restore bound registers. These are nops if Intel MPX isn't - # avaiable or disabled. -# ifdef HAVE_MPX_SUPPORT - bndmov REGISTER_SAVE_BND3(%rsp), %bnd3 - bndmov REGISTER_SAVE_BND2(%rsp), %bnd2 - bndmov REGISTER_SAVE_BND1(%rsp), %bnd1 - bndmov REGISTER_SAVE_BND0(%rsp), %bnd0 + # Get register content back. +# ifdef USE_FXSAVE + fxrstor STATE_SAVE_OFFSET(%rsp) # else - .byte 0x66,0x0f,0x1a,0x5c,0x24,REGISTER_SAVE_BND3 - .byte 0x66,0x0f,0x1a,0x54,0x24,REGISTER_SAVE_BND2 - .byte 0x66,0x0f,0x1a,0x4c,0x24,REGISTER_SAVE_BND1 -# if REGISTER_SAVE_BND0 == 0 - .byte 0x66,0x0f,0x1a,0x04,0x24 -# else - .byte 0x66,0x0f,0x1a,0x44,0x24,REGISTER_SAVE_BND0 -# endif + movl $STATE_SAVE_MASK, %eax + xorl %edx, %edx + xrstor STATE_SAVE_OFFSET(%rsp) # endif -#endif - # Get register content back. movq REGISTER_SAVE_R9(%rsp), %r9 movq REGISTER_SAVE_R8(%rsp), %r8 movq REGISTER_SAVE_RDI(%rsp), %rdi @@ -138,20 +139,12 @@ _dl_runtime_resolve: movq REGISTER_SAVE_RDX(%rsp), %rdx movq REGISTER_SAVE_RCX(%rsp), %rcx movq REGISTER_SAVE_RAX(%rsp), %rax - VMOV (REGISTER_SAVE_VEC_OFF)(%rsp), %VEC(0) - VMOV (REGISTER_SAVE_VEC_OFF + VEC_SIZE)(%rsp), %VEC(1) - VMOV (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 2)(%rsp), %VEC(2) - VMOV (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 3)(%rsp), %VEC(3) - VMOV (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 4)(%rsp), %VEC(4) - VMOV (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 5)(%rsp), %VEC(5) - VMOV (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 6)(%rsp), %VEC(6) - VMOV (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 7)(%rsp), %VEC(7) -#if DL_RUNTIME_RESOLVE_REALIGN_STACK +# if DL_RUNTIME_RESOLVE_REALIGN_STACK mov %RBX_LP, %RSP_LP cfi_def_cfa_register(%rsp) movq (%rsp), %rbx cfi_restore(%rbx) -#endif +# endif # Adjust stack(PLT did 2 pushes) add $(LOCAL_STORAGE_AREA + 16), %RSP_LP cfi_adjust_cfa_offset(-(LOCAL_STORAGE_AREA + 16)) @@ -160,9 +153,10 @@ _dl_runtime_resolve: jmp *%r11 # Jump to function address. cfi_endproc .size _dl_runtime_resolve, .-_dl_runtime_resolve +#endif -#ifndef PROF +#if !defined PROF && defined _dl_runtime_profile # if (LR_VECTOR_OFFSET % VEC_SIZE) != 0 # error LR_VECTOR_OFFSET must be multples of VEC_SIZE # endif diff --git a/sysdeps/x86_64/memcpy_chk.S b/sysdeps/x86_64/memcpy_chk.S index 2296b55119..a95b3ad3cf 100644 --- a/sysdeps/x86_64/memcpy_chk.S +++ b/sysdeps/x86_64/memcpy_chk.S @@ -19,7 +19,7 @@ #include #include "asm-syntax.h" -#ifndef PIC +#ifndef SHARED /* For libc.so this is defined in memcpy.S. For libc.a, this is a separate source to avoid memcpy bringing in __chk_fail and all routines diff --git a/sysdeps/x86_64/multiarch/memcpy.S b/sysdeps/x86_64/multiarch/memcpy.S index b8677596f9..ea4ec70d1a 100644 --- a/sysdeps/x86_64/multiarch/memcpy.S +++ b/sysdeps/x86_64/multiarch/memcpy.S @@ -32,6 +32,8 @@ ENTRY(__new_memcpy) lea __memcpy_erms(%rip), %RAX_LP HAS_ARCH_FEATURE (Prefer_ERMS) jnz 2f + HAS_ARCH_FEATURE (Prefer_No_AVX512) + jnz 1f HAS_ARCH_FEATURE (AVX512F_Usable) jz 1f lea __memcpy_avx512_no_vzeroupper(%rip), %RAX_LP diff --git a/sysdeps/x86_64/multiarch/memcpy_chk.S b/sysdeps/x86_64/multiarch/memcpy_chk.S index 9d92c8a7e3..26b49de6f6 100644 --- a/sysdeps/x86_64/multiarch/memcpy_chk.S +++ b/sysdeps/x86_64/multiarch/memcpy_chk.S @@ -30,6 +30,8 @@ ENTRY(__memcpy_chk) .type __memcpy_chk, @gnu_indirect_function LOAD_RTLD_GLOBAL_RO_RDX + HAS_ARCH_FEATURE (Prefer_No_AVX512) + jnz 1f HAS_ARCH_FEATURE (AVX512F_Usable) jz 1f lea __memcpy_chk_avx512_no_vzeroupper(%rip), %RAX_LP diff --git a/sysdeps/x86_64/multiarch/memmove.S b/sysdeps/x86_64/multiarch/memmove.S index ff5e041420..ef92afde5a 100644 --- a/sysdeps/x86_64/multiarch/memmove.S +++ b/sysdeps/x86_64/multiarch/memmove.S @@ -30,6 +30,8 @@ ENTRY(__libc_memmove) lea __memmove_erms(%rip), %RAX_LP HAS_ARCH_FEATURE (Prefer_ERMS) jnz 2f + HAS_ARCH_FEATURE (Prefer_No_AVX512) + jnz 1f HAS_ARCH_FEATURE (AVX512F_Usable) jz 1f lea __memmove_avx512_no_vzeroupper(%rip), %RAX_LP diff --git a/sysdeps/x86_64/multiarch/memmove_chk.S b/sysdeps/x86_64/multiarch/memmove_chk.S index 7f861206df..a9129c460a 100644 --- a/sysdeps/x86_64/multiarch/memmove_chk.S +++ b/sysdeps/x86_64/multiarch/memmove_chk.S @@ -29,6 +29,8 @@ ENTRY(__memmove_chk) .type __memmove_chk, @gnu_indirect_function LOAD_RTLD_GLOBAL_RO_RDX + HAS_ARCH_FEATURE (Prefer_No_AVX512) + jnz 1f HAS_ARCH_FEATURE (AVX512F_Usable) jz 1f lea __memmove_chk_avx512_no_vzeroupper(%rip), %RAX_LP diff --git a/sysdeps/x86_64/multiarch/mempcpy.S b/sysdeps/x86_64/multiarch/mempcpy.S index 51970687cf..87c8299fea 100644 --- a/sysdeps/x86_64/multiarch/mempcpy.S +++ b/sysdeps/x86_64/multiarch/mempcpy.S @@ -32,6 +32,8 @@ ENTRY(__mempcpy) lea __mempcpy_erms(%rip), %RAX_LP HAS_ARCH_FEATURE (Prefer_ERMS) jnz 2f + HAS_ARCH_FEATURE (Prefer_No_AVX512) + jnz 1f HAS_ARCH_FEATURE (AVX512F_Usable) jz 1f lea __mempcpy_avx512_no_vzeroupper(%rip), %RAX_LP diff --git a/sysdeps/x86_64/multiarch/mempcpy_chk.S b/sysdeps/x86_64/multiarch/mempcpy_chk.S index 9e49f6f26e..642c67973b 100644 --- a/sysdeps/x86_64/multiarch/mempcpy_chk.S +++ b/sysdeps/x86_64/multiarch/mempcpy_chk.S @@ -30,6 +30,8 @@ ENTRY(__mempcpy_chk) .type __mempcpy_chk, @gnu_indirect_function LOAD_RTLD_GLOBAL_RO_RDX + HAS_ARCH_FEATURE (Prefer_No_AVX512) + jnz 1f HAS_ARCH_FEATURE (AVX512F_Usable) jz 1f lea __mempcpy_chk_avx512_no_vzeroupper(%rip), %RAX_LP diff --git a/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S b/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S index 28e71fd576..acf448c9a6 100644 --- a/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S +++ b/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S @@ -110,6 +110,8 @@ ENTRY (__memset_erms) ENTRY (MEMSET_SYMBOL (__memset, erms)) # endif L(stosb): + /* Issue vzeroupper before rep stosb. */ + VZEROUPPER movq %rdx, %rcx movzbl %sil, %eax movq %rdi, %rdx diff --git a/sysdeps/x86_64/multiarch/memset.S b/sysdeps/x86_64/multiarch/memset.S index 96e99341aa..eae39e2ecd 100644 --- a/sysdeps/x86_64/multiarch/memset.S +++ b/sysdeps/x86_64/multiarch/memset.S @@ -41,6 +41,8 @@ ENTRY(memset) jnz L(AVX512F) lea __memset_avx2_unaligned(%rip), %RAX_LP L(AVX512F): + HAS_ARCH_FEATURE (Prefer_No_AVX512) + jnz 2f HAS_ARCH_FEATURE (AVX512F_Usable) jz 2f lea __memset_avx512_no_vzeroupper(%rip), %RAX_LP diff --git a/sysdeps/x86_64/multiarch/memset_chk.S b/sysdeps/x86_64/multiarch/memset_chk.S index 2efe6ed909..38d7bef6df 100644 --- a/sysdeps/x86_64/multiarch/memset_chk.S +++ b/sysdeps/x86_64/multiarch/memset_chk.S @@ -38,6 +38,8 @@ ENTRY(__memset_chk) jnz L(AVX512F) lea __memset_chk_avx2_unaligned(%rip), %RAX_LP L(AVX512F): + HAS_ARCH_FEATURE (Prefer_No_AVX512) + jnz 2f HAS_ARCH_FEATURE (AVX512F_Usable) jz 2f lea __memset_chk_avx512_no_vzeroupper(%rip), %RAX_LP diff --git a/sysdeps/x86_64/nptl/tcb-offsets.sym b/sysdeps/x86_64/nptl/tcb-offsets.sym index aeb752673a..8a25c482cb 100644 --- a/sysdeps/x86_64/nptl/tcb-offsets.sym +++ b/sysdeps/x86_64/nptl/tcb-offsets.sym @@ -4,7 +4,6 @@ RESULT offsetof (struct pthread, result) TID offsetof (struct pthread, tid) -PID offsetof (struct pthread, pid) CANCELHANDLING offsetof (struct pthread, cancelhandling) CLEANUP_JMP_BUF offsetof (struct pthread, cleanup_jmp_buf) CLEANUP offsetof (struct pthread, cleanup) diff --git a/sysdeps/x86_64/rtld-offsets.sym b/sysdeps/x86_64/rtld-offsets.sym new file mode 100644 index 0000000000..fd41b51521 --- /dev/null +++ b/sysdeps/x86_64/rtld-offsets.sym @@ -0,0 +1,6 @@ +#define SHARED +#include + +-- + +GL_TLS_GENERATION_OFFSET offsetof (struct rtld_global, _dl_tls_generation) diff --git a/sysdeps/x86_64/sysdep.h b/sysdeps/x86_64/sysdep.h index 75ac747be8..4b67fa80c1 100644 --- a/sysdeps/x86_64/sysdep.h +++ b/sysdeps/x86_64/sysdep.h @@ -89,13 +89,14 @@ lose: \ END (name) #undef JUMPTARGET -#ifdef PIC +#ifdef SHARED # ifdef BIND_NOW # define JUMPTARGET(name) *name##@GOTPCREL(%rip) # else # define JUMPTARGET(name) name##@PLT # endif #else +/* For static archives, branch to target directly. */ # define JUMPTARGET(name) name #endif diff --git a/sysdeps/x86_64/tls_get_addr.S b/sysdeps/x86_64/tls_get_addr.S new file mode 100644 index 0000000000..9d38fb3be5 --- /dev/null +++ b/sysdeps/x86_64/tls_get_addr.S @@ -0,0 +1,61 @@ +/* Stack-aligning implementation of __tls_get_addr. x86-64 version. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifdef SHARED + +# include +# include "tlsdesc.h" +# include "rtld-offsets.h" + +/* See __tls_get_addr and __tls_get_addr_slow in dl-tls.c. This function + call __tls_get_addr_slow on both slow paths. It realigns the stack + before the call to work around GCC PR58066. */ + +ENTRY (__tls_get_addr) + mov %fs:DTV_OFFSET, %RDX_LP + mov GL_TLS_GENERATION_OFFSET+_rtld_local(%rip), %RAX_LP + /* GL(dl_tls_generation) == dtv[0].counter */ + cmp %RAX_LP, (%rdx) + jne 1f + mov TI_MODULE_OFFSET(%rdi), %RAX_LP + /* dtv[ti->ti_module] */ +# ifdef __LP64__ + salq $4, %rax + movq (%rdx,%rax), %rax +# else + movl (%rdx,%rax, 8), %eax +# endif + cmp $-1, %RAX_LP + je 1f + add TI_OFFSET_OFFSET(%rdi), %RAX_LP + ret +1: + /* On the slow path, align the stack. */ + pushq %rbp + cfi_def_cfa_offset (16) + cfi_offset (%rbp, -16) + mov %RSP_LP, %RBP_LP + cfi_def_cfa_register (%rbp) + and $-16, %RSP_LP + call __tls_get_addr_slow + mov %RBP_LP, %RSP_LP + popq %rbp + cfi_def_cfa (%rsp, 8) + ret +END (__tls_get_addr) +#endif /* SHARED */ diff --git a/sysdeps/x86_64/tlsdesc.sym b/sysdeps/x86_64/tlsdesc.sym index 33854975d0..fc897ab4b5 100644 --- a/sysdeps/x86_64/tlsdesc.sym +++ b/sysdeps/x86_64/tlsdesc.sym @@ -15,3 +15,6 @@ TLSDESC_ARG offsetof(struct tlsdesc, arg) TLSDESC_GEN_COUNT offsetof(struct tlsdesc_dynamic_arg, gen_count) TLSDESC_MODID offsetof(struct tlsdesc_dynamic_arg, tlsinfo.ti_module) TLSDESC_MODOFF offsetof(struct tlsdesc_dynamic_arg, tlsinfo.ti_offset) + +TI_MODULE_OFFSET offsetof(tls_index, ti_module) +TI_OFFSET_OFFSET offsetof(tls_index, ti_offset) diff --git a/sysdeps/x86_64/tst-avx-aux.c b/sysdeps/x86_64/tst-avx-aux.c new file mode 100644 index 0000000000..e3807de7bb --- /dev/null +++ b/sysdeps/x86_64/tst-avx-aux.c @@ -0,0 +1,47 @@ +/* Test case for preserved AVX registers in dynamic linker, -mavx part. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include + +int +tst_avx_aux (void) +{ +#ifdef __AVX__ + extern __m256i avx_test (__m256i, __m256i, __m256i, __m256i, + __m256i, __m256i, __m256i, __m256i); + + __m256i ymm0 = _mm256_set1_epi32 (0); + __m256i ymm1 = _mm256_set1_epi32 (1); + __m256i ymm2 = _mm256_set1_epi32 (2); + __m256i ymm3 = _mm256_set1_epi32 (3); + __m256i ymm4 = _mm256_set1_epi32 (4); + __m256i ymm5 = _mm256_set1_epi32 (5); + __m256i ymm6 = _mm256_set1_epi32 (6); + __m256i ymm7 = _mm256_set1_epi32 (7); + __m256i ret = avx_test (ymm0, ymm1, ymm2, ymm3, + ymm4, ymm5, ymm6, ymm7); + ymm0 = _mm256_set1_epi32 (0x12349876); + if (memcmp (&ymm0, &ret, sizeof (ret))) + abort (); + return 0; +#else /* __AVX__ */ + return 77; +#endif /* __AVX__ */ +} diff --git a/sysdeps/x86_64/tst-avx.c b/sysdeps/x86_64/tst-avx.c new file mode 100644 index 0000000000..ec2e3a79ff --- /dev/null +++ b/sysdeps/x86_64/tst-avx.c @@ -0,0 +1,49 @@ +/* Test case for preserved AVX registers in dynamic linker. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +int tst_avx_aux (void); + +static int +avx_enabled (void) +{ + unsigned int eax, ebx, ecx, edx; + + if (__get_cpuid (1, &eax, &ebx, &ecx, &edx) == 0 + || (ecx & (bit_AVX | bit_OSXSAVE)) != (bit_AVX | bit_OSXSAVE)) + return 0; + + /* Check the OS has AVX and SSE saving enabled. */ + asm ("xgetbv" : "=a" (eax), "=d" (edx) : "c" (0)); + + return (eax & 6) == 6; +} + +static int +do_test (void) +{ + /* Run AVX test only if AVX is supported. */ + if (avx_enabled ()) + return tst_avx_aux (); + else + return 77; +} + +#define TEST_FUNCTION do_test () +#include "../../test-skeleton.c" diff --git a/sysdeps/x86_64/tst-avx512-aux.c b/sysdeps/x86_64/tst-avx512-aux.c new file mode 100644 index 0000000000..6cebc523f2 --- /dev/null +++ b/sysdeps/x86_64/tst-avx512-aux.c @@ -0,0 +1,48 @@ +/* Test case for preserved AVX512 registers in dynamic linker, + -mavx512 part. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include + +int +tst_avx512_aux (void) +{ +#ifdef __AVX512F__ + extern __m512i avx512_test (__m512i, __m512i, __m512i, __m512i, + __m512i, __m512i, __m512i, __m512i); + + __m512i zmm0 = _mm512_set1_epi32 (0); + __m512i zmm1 = _mm512_set1_epi32 (1); + __m512i zmm2 = _mm512_set1_epi32 (2); + __m512i zmm3 = _mm512_set1_epi32 (3); + __m512i zmm4 = _mm512_set1_epi32 (4); + __m512i zmm5 = _mm512_set1_epi32 (5); + __m512i zmm6 = _mm512_set1_epi32 (6); + __m512i zmm7 = _mm512_set1_epi32 (7); + __m512i ret = avx512_test (zmm0, zmm1, zmm2, zmm3, + zmm4, zmm5, zmm6, zmm7); + zmm0 = _mm512_set1_epi32 (0x12349876); + if (memcmp (&zmm0, &ret, sizeof (ret))) + abort (); + return 0; +#else /* __AVX512F__ */ + return 77; +#endif /* __AVX512F__ */ +} diff --git a/sysdeps/x86_64/tst-avx512.c b/sysdeps/x86_64/tst-avx512.c new file mode 100644 index 0000000000..a8e42ef553 --- /dev/null +++ b/sysdeps/x86_64/tst-avx512.c @@ -0,0 +1,57 @@ +/* Test case for preserved AVX512 registers in dynamic linker. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +int tst_avx512_aux (void); + +static int +avx512_enabled (void) +{ +#ifdef bit_AVX512F + unsigned int eax, ebx, ecx, edx; + + if (__get_cpuid (1, &eax, &ebx, &ecx, &edx) == 0 + || (ecx & (bit_AVX | bit_OSXSAVE)) != (bit_AVX | bit_OSXSAVE)) + return 0; + + __cpuid_count (7, 0, eax, ebx, ecx, edx); + if (!(ebx & bit_AVX512F)) + return 0; + + asm ("xgetbv" : "=a" (eax), "=d" (edx) : "c" (0)); + + /* Verify that ZMM, YMM and XMM states are enabled. */ + return (eax & 0xe6) == 0xe6; +#else + return 0; +#endif +} + +static int +do_test (void) +{ + /* Run AVX512 test only if AVX512 is supported. */ + if (avx512_enabled ()) + return tst_avx512_aux (); + else + return 77; +} + +#define TEST_FUNCTION do_test () +#include "../../test-skeleton.c" diff --git a/sysdeps/x86_64/tst-avx512mod.c b/sysdeps/x86_64/tst-avx512mod.c new file mode 100644 index 0000000000..4cfb3a2c3d --- /dev/null +++ b/sysdeps/x86_64/tst-avx512mod.c @@ -0,0 +1,48 @@ +/* Test case for x86-64 preserved AVX512 registers in dynamic linker. */ + +#ifdef __AVX512F__ +#include +#include +#include + +__m512i +avx512_test (__m512i x0, __m512i x1, __m512i x2, __m512i x3, + __m512i x4, __m512i x5, __m512i x6, __m512i x7) +{ + __m512i zmm; + + zmm = _mm512_set1_epi32 (0); + if (memcmp (&zmm, &x0, sizeof (zmm))) + abort (); + + zmm = _mm512_set1_epi32 (1); + if (memcmp (&zmm, &x1, sizeof (zmm))) + abort (); + + zmm = _mm512_set1_epi32 (2); + if (memcmp (&zmm, &x2, sizeof (zmm))) + abort (); + + zmm = _mm512_set1_epi32 (3); + if (memcmp (&zmm, &x3, sizeof (zmm))) + abort (); + + zmm = _mm512_set1_epi32 (4); + if (memcmp (&zmm, &x4, sizeof (zmm))) + abort (); + + zmm = _mm512_set1_epi32 (5); + if (memcmp (&zmm, &x5, sizeof (zmm))) + abort (); + + zmm = _mm512_set1_epi32 (6); + if (memcmp (&zmm, &x6, sizeof (zmm))) + abort (); + + zmm = _mm512_set1_epi32 (7); + if (memcmp (&zmm, &x7, sizeof (zmm))) + abort (); + + return _mm512_set1_epi32 (0x12349876); +} +#endif diff --git a/sysdeps/x86_64/tst-avxmod.c b/sysdeps/x86_64/tst-avxmod.c new file mode 100644 index 0000000000..6e5b154997 --- /dev/null +++ b/sysdeps/x86_64/tst-avxmod.c @@ -0,0 +1,48 @@ +/* Test case for x86-64 preserved AVX registers in dynamic linker. */ + +#ifdef __AVX__ +#include +#include +#include + +__m256i +avx_test (__m256i x0, __m256i x1, __m256i x2, __m256i x3, + __m256i x4, __m256i x5, __m256i x6, __m256i x7) +{ + __m256i ymm; + + ymm = _mm256_set1_epi32 (0); + if (memcmp (&ymm, &x0, sizeof (ymm))) + abort (); + + ymm = _mm256_set1_epi32 (1); + if (memcmp (&ymm, &x1, sizeof (ymm))) + abort (); + + ymm = _mm256_set1_epi32 (2); + if (memcmp (&ymm, &x2, sizeof (ymm))) + abort (); + + ymm = _mm256_set1_epi32 (3); + if (memcmp (&ymm, &x3, sizeof (ymm))) + abort (); + + ymm = _mm256_set1_epi32 (4); + if (memcmp (&ymm, &x4, sizeof (ymm))) + abort (); + + ymm = _mm256_set1_epi32 (5); + if (memcmp (&ymm, &x5, sizeof (ymm))) + abort (); + + ymm = _mm256_set1_epi32 (6); + if (memcmp (&ymm, &x6, sizeof (ymm))) + abort (); + + ymm = _mm256_set1_epi32 (7); + if (memcmp (&ymm, &x7, sizeof (ymm))) + abort (); + + return _mm256_set1_epi32 (0x12349876); +} +#endif diff --git a/sysdeps/x86_64/tst-sse.c b/sysdeps/x86_64/tst-sse.c new file mode 100644 index 0000000000..dd1537cf27 --- /dev/null +++ b/sysdeps/x86_64/tst-sse.c @@ -0,0 +1,46 @@ +/* Test case for preserved SSE registers in dynamic linker. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include + +extern __m128i sse_test (__m128i, __m128i, __m128i, __m128i, + __m128i, __m128i, __m128i, __m128i); + +static int +do_test (void) +{ + __m128i xmm0 = _mm_set1_epi32 (0); + __m128i xmm1 = _mm_set1_epi32 (1); + __m128i xmm2 = _mm_set1_epi32 (2); + __m128i xmm3 = _mm_set1_epi32 (3); + __m128i xmm4 = _mm_set1_epi32 (4); + __m128i xmm5 = _mm_set1_epi32 (5); + __m128i xmm6 = _mm_set1_epi32 (6); + __m128i xmm7 = _mm_set1_epi32 (7); + __m128i ret = sse_test (xmm0, xmm1, xmm2, xmm3, + xmm4, xmm5, xmm6, xmm7); + xmm0 = _mm_set1_epi32 (0x12349876); + if (memcmp (&xmm0, &ret, sizeof (ret))) + abort (); + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../../test-skeleton.c" diff --git a/sysdeps/x86_64/tst-ssemod.c b/sysdeps/x86_64/tst-ssemod.c new file mode 100644 index 0000000000..907a64c69e --- /dev/null +++ b/sysdeps/x86_64/tst-ssemod.c @@ -0,0 +1,46 @@ +/* Test case for x86-64 preserved SSE registers in dynamic linker. */ + +#include +#include +#include + +__m128i +sse_test (__m128i x0, __m128i x1, __m128i x2, __m128i x3, + __m128i x4, __m128i x5, __m128i x6, __m128i x7) +{ + __m128i xmm; + + xmm = _mm_set1_epi32 (0); + if (memcmp (&xmm, &x0, sizeof (xmm))) + abort (); + + xmm = _mm_set1_epi32 (1); + if (memcmp (&xmm, &x1, sizeof (xmm))) + abort (); + + xmm = _mm_set1_epi32 (2); + if (memcmp (&xmm, &x2, sizeof (xmm))) + abort (); + + xmm = _mm_set1_epi32 (3); + if (memcmp (&xmm, &x3, sizeof (xmm))) + abort (); + + xmm = _mm_set1_epi32 (4); + if (memcmp (&xmm, &x4, sizeof (xmm))) + abort (); + + xmm = _mm_set1_epi32 (5); + if (memcmp (&xmm, &x5, sizeof (xmm))) + abort (); + + xmm = _mm_set1_epi32 (6); + if (memcmp (&xmm, &x6, sizeof (xmm))) + abort (); + + xmm = _mm_set1_epi32 (7); + if (memcmp (&xmm, &x7, sizeof (xmm))) + abort (); + + return _mm_set1_epi32 (0x12349876); +}