GIT update of https://sourceware.org/git/glibc.git/release/2.28/master from glibc-2.28 diff --git a/ChangeLog b/ChangeLog index 08b42bd2f5..63917cc15d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,822 @@ +2019-04-23 Adhemerval Zanella + + [BZ #18035] + * elf/pldd-xx.c: Use _Static_assert in of pldd_assert. + (E(find_maps)): Avoid use alloca, use default read file operations + instead of explicit LFS names, and fix infinite loop. + * elf/pldd.c: Explicit set _FILE_OFFSET_BITS, cleanup headers. + (get_process_info): Use _Static_assert instead of assert, use default + directory operations instead of explicit LFS names, and free some + leadek pointers. + +2019-04-03 TAMUKI Shoichi + + [BZ #22964] + * localedata/locales/ja_JP (LC_TIME): Add entry for the new Japanese + era. + +2019-03-21 Stefan Liebler + + * sysdeps/s390/dl-procinfo.h (HWCAP_IMPORTANT): + Add HWCAP_S390_VX and HWCAP_S390_VXE. + +2019-01-31 Paul Eggert + + CVE-2019-9169 + regex: fix read overrun [BZ #24114] + Problem found by AddressSanitizer, reported by Hongxu Chen in: + https://debbugs.gnu.org/34140 + * posix/regexec.c (proceed_next_node): + Do not read past end of input buffer. + +2018-11-07 Andreas Schwab + + [BZ #23864] + * sysdeps/unix/sysv/linux/riscv/kernel-features.h + (__ASSUME_SET_ROBUST_LIST) [__LINUX_KERNEL_VERSION < 0x041400]: + Undef. + +2018-09-21 Adhemerval Zanella + + * NEWS: Add note about new TLE support on powerpc64le. + * sysdeps/powerpc/nptl/tcb-offsets.sym (TM_CAPABLE): Remove. + * sysdeps/powerpc/nptl/tls.h (tcbhead_t): Rename tm_capable to + __ununsed1. + (TLS_INIT_TP, TLS_DEFINE_INIT_TP): Remove tm_capable setup. + (THREAD_GET_TM_CAPABLE, THREAD_SET_TM_CAPABLE): Remove macros. + * sysdeps/powerpc/powerpc32/sysdep.h, + sysdeps/powerpc/powerpc64/sysdep.h (ABORT_TRANSACTION_IMPL, + ABORT_TRANSACTION): Remove macros. + * sysdeps/powerpc/sysdep.h (ABORT_TRANSACTION): Likewise. + * sysdeps/unix/sysv/linux/powerpc/elision-conf.c (elision_init): Set + __pthread_force_elision iff PPC_FEATURE2_HTM_NOSC is set. + * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h, + sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h + sysdeps/unix/sysv/linux/powerpc/syscall.S (ABORT_TRANSACTION): Remove + usage. + * sysdeps/unix/sysv/linux/powerpc/not-errno.h: Remove file. + +2019-01-13 Jim Wilson + + [BZ #24040] + * elf/Makefile (CFLAGS-tst-unwind-main.c): Add -DUSE_PTHREADS=0. + * elf/tst-unwind-main.c: If USE_PTHEADS, include pthread.h and error.h + (func): New. + (main): If USE_PTHREADS, call pthread_create to run func. Otherwise + call func directly. + * nptl/Makefile (tests): Add tst-unwind-thread. + (CFLAGS-tst-unwind-thread.c): Define. + * nptl/tst-unwind-thread.c: New file. + * sysdeps/unix/sysv/linux/riscv/clone.S (__thread_start): Mark ra + as undefined. + +2019-01-31 Carlos O'Donell + Torvald Riegel + Rik Prohaska + + [BZ# 23844] + * nptl/Makefile (tests): Add tst-rwlock-tryrdlock-stall, and + tst-rwlock-trywrlock-stall. + * nptl/pthread_rwlock_tryrdlock.c (__pthread_rwlock_tryrdlock): + Wake waiters if PTHREAD_RWLOCK_FUTEX_USED is set. + * nptl/pthread_rwlock_trywrlock.c (__pthread_rwlock_trywrlock): + Set __wrphase_fute to 1 only if we started the write phase. + * nptl/tst-rwlock-tryrdlock-stall.c: New file. + * nptl/tst-rwlock-trywrlock-stall.c: New file. + * support/Makefile (libsupport-routines): Add xpthread_rwlock_destroy. + * support/xpthread_rwlock_destroy.c: New file. + * support/xthread.h: Declare xpthread_rwlock_destroy. + +2019-02-08 Florian Weimer + + [BZ #24161] + * sysdeps/nptl/fork.h (__run_fork_handlers): Add multiple_threads + argument. + * nptl/register-atfork.c (__run_fork_handlers): Only perform + locking if the new do_locking argument is true. + * sysdeps/nptl/fork.c (__libc_fork): Pass multiple_threads to + __run_fork_handlers. + +2019-02-07 Stefan Liebler + + [BZ #24180] + * nptl/pthread_mutex_trylock.c (__pthread_mutex_trylock): + Add compiler barriers and comments. + +2019-02-04 Florian Weimer + + [BZ #20018] + nscd: Do not rely on new GLIBC_PRIVATE ABI after CVE-2016-10739 fix. + * nscd/nscd-inet_addr.c: New file. Build resolv/inet_addr.c for + nscd, without public symbols. + * nscd/Makefile (nscd-modules): Add it. + * nscd/gai.c: Include and change visibility of + __inet_aton_exact. + +2019-01-21 Florian Weimer + + [BZ #20018] + CVE-2016-10739 + resolv: Reject trailing characters in host names + * include/arpa/inet.h (__inet_aton_exact): Declare. + (inet_aton): Remove hidden prototype. No longer used internally. + * nscd/gai.c (__inet_aton): Do not define. + * nscd/gethstbynm3_r.c (__inet_aton): Likewise. + * nss/digits_dots.c (__inet_aton): Likewise. + (__nss_hostname_digits_dots_context): Call __inet_aton_exact. + * resolv/Makefile (tests-internal): Add tst-inet_aton_exact. + (tests): Add tst-resolv-nondecimal, tst-resolv-trailing. + (tst-resolv-nondecimal): Link with libresolv.so and libpthread. + (tst-resolv-trailing): Likewise. + * resolv/Versions (GLIBC_PRIVATE): Export __inet_aton_exact from + libc. + * resolv/inet_addr.c (inet_aton_end): Remame from __inet_aton. + Make static. Add endp parameter. + (__inet_aton_exact): New function. + (__inet_aton_ignore_trailing): New function, aliased to inet_aton. + (__inet_addr): Call inet_aton_end. + * resolv/res_init.c (res_vinit_1): Truncate nameserver for IPv4, + not just IPv6. Call __inet_aton_exact. + * resolv/tst-aton.c: Switch to . + (tests): Make const. Add additional test cases with trailing + characters. + (do_test): Use array_length. + * resolv/tst-inet_aton_exact.c: New file. + * resolv/tst-resolv-trailing.c: Likewise. + * resolv/tst-resolv-nondecimal.c: Likewise. + * sysdeps/posix/getaddrinfo.c (gaih_inet): Call __inet_aton_exact. + +2019-01-18 Florian Weimer + + [BZ #24112] + resolv: Do not send queries for non-host-names in nss_dns. + * resolv/nss_dns/dns-host.c (check_name): New function. + (_nss_dns_gethostbyname2_r): Use it. + (_nss_dns_gethostbyname_r): Likewise. + (_nss_dns_gethostbyname4_r): Likewise. + +2019-01-21 Florian Weimer + + * resolv/inet_addr.c: Reformat to GNU style. + (__inet_addr, __inet_aton): Update comment. + +2019-02-04 H.J. Lu + + [BZ #24155] + CVE-2019-7309 + * NEWS: Updated for CVE-2019-7309. + * sysdeps/x86_64/memcmp.S: Use RDX_LP for size. Clear the + upper 32 bits of RDX register for x32. Use unsigned Jcc + instructions, instead of signed. + * sysdeps/x86_64/x32/Makefile (tests): Add tst-size_t-memcmp-2. + * sysdeps/x86_64/x32/tst-size_t-memcmp-2.c: New test. + +2019-02-01 H.J. Lu + + [BZ #24097] + CVE-2019-6488 + * sysdeps/x86_64/multiarch/strlen-avx2.S: Use RSI_LP for length. + Clear the upper 32 bits of RSI register. + * sysdeps/x86_64/strlen.S: Use RSI_LP for length. + * sysdeps/x86_64/x32/Makefile (tests): Add tst-size_t-strnlen + and tst-size_t-wcsnlen. + * sysdeps/x86_64/x32/tst-size_t-strnlen.c: New file. + * sysdeps/x86_64/x32/tst-size_t-wcsnlen.c: Likewise. + +2019-02-01 H.J. Lu + + [BZ #24097] + CVE-2019-6488 + * sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S: Use RDX_LP + for length. + * sysdeps/x86_64/multiarch/strcpy-ssse3.S: Likewise. + * sysdeps/x86_64/x32/Makefile (tests): Add tst-size_t-strncpy. + * sysdeps/x86_64/x32/tst-size_t-strncpy.c: New file. + +2019-02-01 H.J. Lu + + [BZ #24097] + CVE-2019-6488 + * sysdeps/x86_64/multiarch/strcmp-avx2.S: Use RDX_LP for length. + * sysdeps/x86_64/multiarch/strcmp-sse42.S: Likewise. + * sysdeps/x86_64/strcmp.S: Likewise. + * sysdeps/x86_64/x32/Makefile (tests): Add tst-size_t-strncasecmp, + tst-size_t-strncmp and tst-size_t-wcsncmp. + * sysdeps/x86_64/x32/tst-size_t-strncasecmp.c: New file. + * sysdeps/x86_64/x32/tst-size_t-strncmp.c: Likewise. + * sysdeps/x86_64/x32/tst-size_t-wcsncmp.c: Likewise. + +2019-02-01 H.J. Lu + + [BZ #24097] + CVE-2019-6488 + * sysdeps/x86_64/multiarch/memset-avx512-no-vzeroupper.S: Use + RDX_LP for length. Clear the upper 32 bits of RDX register. + * sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S: Likewise. + * sysdeps/x86_64/x32/Makefile (tests): Add tst-size_t-wmemset. + * sysdeps/x86_64/x32/tst-size_t-memset.c: New file. + * sysdeps/x86_64/x32/tst-size_t-wmemset.c: Likewise. + +2019-02-01 H.J. Lu + + [BZ #24097] + CVE-2019-6488 + * sysdeps/x86_64/memrchr.S: Use RDX_LP for length. + * sysdeps/x86_64/multiarch/memrchr-avx2.S: Likewise. + * sysdeps/x86_64/x32/Makefile (tests): Add tst-size_t-memrchr. + * sysdeps/x86_64/x32/tst-size_t-memrchr.c: New file. + +2019-02-01 H.J. Lu + + [BZ #24097] + CVE-2019-6488 + * sysdeps/x86_64/multiarch/memcpy-ssse3-back.S: Use RDX_LP for + length. Clear the upper 32 bits of RDX register. + * sysdeps/x86_64/multiarch/memcpy-ssse3.S: Likewise. + * sysdeps/x86_64/multiarch/memmove-avx512-no-vzeroupper.S: + Likewise. + * sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S: + Likewise. + * sysdeps/x86_64/x32/Makefile (tests): Add tst-size_t-memcpy. + tst-size_t-wmemchr. + * sysdeps/x86_64/x32/tst-size_t-memcpy.c: New file. + +2019-02-01 H.J. Lu + + [BZ #24097] + CVE-2019-6488 + * sysdeps/x86_64/multiarch/memcmp-avx2-movbe.S: Use RDX_LP for + length. Clear the upper 32 bits of RDX register. + * sysdeps/x86_64/multiarch/memcmp-sse4.S: Likewise. + * sysdeps/x86_64/multiarch/memcmp-ssse3.S: Likewise. + * sysdeps/x86_64/x32/Makefile (tests): Add tst-size_t-memcmp and + tst-size_t-wmemcmp. + * sysdeps/x86_64/x32/tst-size_t-memcmp.c: New file. + * sysdeps/x86_64/x32/tst-size_t-wmemcmp.c: Likewise. + +2019-02-01 H.J. Lu + + [BZ #24097] + CVE-2019-6488 + * sysdeps/x86_64/memchr.S: Use RDX_LP for length. Clear the + upper 32 bits of RDX register. + * sysdeps/x86_64/multiarch/memchr-avx2.S: Likewise. + * sysdeps/x86_64/x32/Makefile (tests): Add tst-size_t-memchr and + tst-size_t-wmemchr. + * sysdeps/x86_64/x32/test-size_t.h: New file. + * sysdeps/x86_64/x32/tst-size_t-memchr.c: Likewise. + * sysdeps/x86_64/x32/tst-size_t-wmemchr.c: Likewise. + +2019-01-16 Tulio Magno Quites Machado Filho + + * math/libm-test-fma.inc (fma_test_data): Set + XFAIL_ROUNDING_IBM128_LIBGCC to more tests. + +2019-01-07 Aurelien Jarno + + [BZ #24024] + * Makeconfig: Build libm with -fno-math-errno but build the remaining + code with -fmath-errno. + * string/Makefile [$(build-shared)] (tests): Add test-strerror-errno. + [$(build-shared)] (LDLIBS-test-strerror-errno): New variable. + * string/test-strerror-errno.c: New file. + +2019-01-03 Martin Jansa + + [BZ #19444] + * sysdeps/ieee754/soft-fp/s_fdiv.c: Include and use + DIAG_PUSH_NEEDS_COMMENT, DIAG_IGNORE_NEEDS_COMMENT and + DIAG_POP_NEEDS_COMMENT to disable -Wmaybe-uninitialized. + +2019-01-02 Aurelien Jarno + + [BZ #24034] + * sysdeps/unix/sysv/linux/arm/atomic-machine.h + (__arm_assisted_compare_and_exchange_val_32_acq): Use uint32_t rather + than __typeof (...) for the a_ptr variable. + +2018-12-31 H.J. Lu + + [BZ #24022] + * sysdeps/unix/sysv/linux/riscv/flush-icache.c: Check if + exists with __has_include__ before including it. + +2019-01-02 Florian Weimer + + [BZ #24018] + * intl/dcigettext.c (DCIGETTEXT): Do not return NULL on asprintf + failure. + +2018-12-31 Florian Weimer + + [BZ #24027] + * malloc/malloc.c (_int_realloc): Always call memcpy for the + copying operation. (ncopies had the wrong type, resulting in an + integer wraparound and too few elements being copied.) + +2018-12-28 Aurelien Jarno + + * sysdeps/alpha/fpu/libm-test-ulps: Regenerated. + +2018-12-18 Adhemerval Zanella + James Clarke + + [BZ #23967] + * sysdeps/unix/sysv/linux/kernel_sigaction.h (HAS_SA_RESTORER): + Define if SA_RESTORER is defined. + (kernel_sigaction): Define sa_restorer if HAS_SA_RESTORER is defined. + (SET_SA_RESTORER, RESET_SA_RESTORER): Define iff the macro are not + already defined. + * sysdeps/unix/sysv/linux/m68k/kernel_sigaction.h (SA_RESTORER, + kernel_sigaction, SET_SA_RESTORER, RESET_SA_RESTORER): Remove + definitions. + (HAS_SA_RESTORER): Define. + * sysdeps/unix/sysv/linux/sparc/kernel_sigaction.h (SA_RESTORER, + SET_SA_RESTORER, RESET_SA_RESTORER): Remove definition. + (HAS_SA_RESTORER): Define. + * sysdeps/unix/sysv/linux/nios2/kernel_sigaction.h: Include generic + kernel_sigaction after define SET_SA_RESTORER and RESET_SA_RESTORER. + * sysdeps/unix/sysv/linux/powerpc/kernel_sigaction.h: Likewise. + * sysdeps/unix/sysv/linux/s390/kernel_sigaction.h: Likewise. + * sysdeps/unix/sysv/linux/x86_64/sigaction.c: Likewise. + +2018-10-30 Andreas Schwab + + [BZ #23125] + * sysdeps/riscv/start.S (ENTRY_POINT): Mark ra as undefined. + Don't use tail call. + * elf/tst-unwind-main.c: New file. + * elf/Makefile (tests): Add tst-unwind-main. + (CFLAGS-tst-unwind-main.c): Define. + +2018-12-15 Florian Weimer + + * support/blob_repeat.c (check_mul_overflow_size_t): New function. + (minimum_stride_size): Use it. + (support_blob_repeat_allocate): Likewise. + +2018-12-13 Andreas Schwab + + [BZ #23861] + * nptl/pthread_rwlock_common.c: Reindent. Fix typos. + (__pthread_rwlock_rdlock_full): Update expected value for + __readers while waiting on PTHREAD_RWLOCK_RWAITING. + * nptl/tst-rwlock-pwn.c: New file. + * nptl/Makefile (tests): Add tst-rwlock-pwn. + +2018-12-12 Tulio Magno Quites Machado Filho + + [BZ #23614] + * sysdeps/powerpc/powerpc64/addmul_1.S (FUNC): Add CFI offset for + registers saved in the stack frame. + * sysdeps/powerpc/powerpc64/lshift.S (__mpn_lshift): Likewise. + * sysdeps/powerpc/powerpc64/mul_1.S (__mpn_mul_1): Likewise. + +2018-12-07 DJ Delorie + + [BZ #23907] + * malloc/tst-tcfree3.c: New. + * malloc/Makefile: Add it. + +2018-12-07 Florian Weimer + + [BZ #23927] + CVE-2018-19591 + * inet/tst-if_index-long.c: New file. + * inet/Makefile (tests): Add tst-if_index-long. + +2018-12-07 Florian Weimer + + * support/check.h (support_record_failure_is_failed): Declare. + * support/descriptors.h: New file. + * support/support_descriptors.c: Likewise. + * support/tst-support_descriptors.c: Likewise. + * support/support_record_failure.c + (support_record_failure_is_failed): New function. + * support/Makefile (libsupport-routines): Add support_descriptors. + (tests): Add tst-support_descriptors. + +2018-12-01 Florian Weimer + + * support/support_capture_subprocess.c + (support_capture_subprocess): Check that pipe descriptors have + expected values. Close original pipe descriptors in subprocess. + +2018-11-28 Florian Weimer + + * support/support.h (support_quote_string): Do not use str + parameter name. + +2018-11-27 Florian Weimer + + * support/support.h (support_quote_string): Declare. + * support/support_quote_string.c: New file. + * support/tst-support_quote_string.c: Likewise. + * support/Makefile (libsupport-routines): Add + support_quote_string. + (tests): Add tst-support_quote_string. + +2018-12-10 Florian Weimer + + [BZ #23972] + * sysdeps/unix/sysv/linux/getdents64.c (handle_overflow): Check + offset instead of count for clarity. Fix typo in comment. + (__old_getdents64): Keep track of previous offset. Use it to call + handle_overflow. + * sysdeps/unix/sysv/linux/tst-readdir64-compat.c (do_test): Check + that d_off is never zero. + +2018-11-30 Tulio Magno Quites Machado Filho + + [BZ #23690] + * elf/dl-runtime.c (_dl_profile_fixup): Guarantee memory + modification order when accessing reloc_result->addr. + * include/link.h (reloc_result): Add field init. + * nptl/Makefile (tests): Add tst-audit-threads. + (modules-names): Add tst-audit-threads-mod1 and + tst-audit-threads-mod2. + Add rules to build tst-audit-threads. + * nptl/tst-audit-threads-mod1.c: New file. + * nptl/tst-audit-threads-mod2.c: Likewise. + * nptl/tst-audit-threads.c: Likewise. + * nptl/tst-audit-threads.h: Likewise. + +2018-11-26 Florian Weimer + + [BZ #23907] + * malloc/malloc.c (_int_free): Validate tc_idx before checking for + double-frees. + + +2018-11-20 DJ Delorie + + * malloc/malloc.c (tcache_entry): Add key field. + (tcache_put): Set it. + (tcache_get): Likewise. + (_int_free): Check for double free in tcache. + * malloc/tst-tcfree1.c: New. + * malloc/tst-tcfree2.c: New. + * malloc/Makefile: Run the new tests. + * manual/probes.texi: Document memory_tcache_double_free probe. + + * dlfcn/dlerror.c (check_free): Prevent double frees. + +2018-11-27 Florian Weimer + + [BZ #23927] + CVE-2018-19591 + * sysdeps/unix/sysv/linux/if_index.c (__if_nametoindex): Avoid + descriptor leak in case of ENODEV error. + +2018-11-19 Florian Weimer + + support: Print timestamps in timeout handler. + * support/support_test_main.c (print_timestamp): New function. + (signal_handler): Use it to print the termination time and the + time of the last write to standard output. + +2018-10-09 Szabolcs Nagy + + * libio/tst-readline.c (TIMEOUT): Define. + +2018-10-22 Joseph Myers + + * sysdeps/unix/sysv/linux/syscall-names.list: Update kernel + version to 4.19. + +2018-09-18 Paul Eggert + + Fix tzfile low-memory assertion failure + [BZ #21716] + * time/tzfile.c (__tzfile_read): Check for memory exhaustion + when registering time zone abbreviations. + +2018-08-31 Paul Pluzhnikov + + [BZ #20271] + * include/stdio.h (__libc_fatal): Mention newline in comment. + * grp/initgroups.c (internal_getgrouplist): Add missing newline. + * nptl/pthread_cond_wait.c (__pthread_cond_wait_common): Likewise. + * nscd/initgrcache.c (addinitgroupsX): Likewise. + * nss/nsswitch.c (__nss_next2): Likewise. + * sysdeps/aarch64/dl-irel.h (elf_irela): Likewise. + * sysdeps/arm/dl-irel.h (elf_irel): Likewise. + * sysdeps/generic/unwind-dw2.c (execute_cfa_program): Likewise. + * sysdeps/i386/dl-irel.h (elf_irel): Likewise. + * sysdeps/powerpc/powerpc32/dl-irel.h (elf_irel): Likewise. + * sysdeps/powerpc/powerpc64/dl-irel.h (elf_irel): Likewise. + * sysdeps/s390/dl-irel.h (elf_irel): Likewise. + * sysdeps/sparc/sparc32/dl-irel.h (elf_irel): Likewise. + * sysdeps/sparc/sparc64/dl-irel.h (elf_irel): Likewise. + * sysdeps/x86_64/dl-irel.h (elf_irel): Likewise. + * sysdeps/nptl/futex-internal.h (futex_wake): Likewise. + * sysdeps/unix/sysv/linux/netlink_assert_response.c + (__netlink_assert_response): Likewise. + +2018-08-28 Florian Weimer + + [BZ #23520] + nscd: Fix use-after-free in addgetnetgrentX and its callers. + * nscd/netgroupcache.c + (addgetnetgrentX): Add tofreep parameter. Do not free + heap-allocated buffer. + (addinnetgrX): Free buffer allocated bt addgetnetgrentX. + (addgetnetgrentX_ignore): New function. + (addgetnetgrent): Call it. + (readdgetnetgrent): Likewise. + +2018-08-16 DJ Delorie + + * malloc/malloc.c (_int_free): Check for corrupt prev_size vs size. + (malloc_consolidate): Likewise. + +2018-08-16 Pochang Chen + + * malloc/malloc.c (_int_malloc.c): Verify size of top chunk. + +2018-08-13 Joseph Myers + + * sysdeps/unix/sysv/linux/syscall-names.list: Update kernel + version to 4.18. + (io_pgetevents): New syscall. + (rseq): Likewise. + +2018-11-08 Alexandra Hájková + + [BZ #17630] + * resolv/tst-resolv-network.c: Add test for getnetbyname. + +2018-11-08 H.J. Lu + + [BZ #23509] + * sysdeps/x86/dl-prop.h (_dl_process_cet_property_note): Skip + note parsing if a NT_GNU_PROPERTY_TYPE_0 note has been processed. + Update the l_cet field when processing NT_GNU_PROPERTY_TYPE_0 note. + Check multiple NT_GNU_PROPERTY_TYPE_0 notes. + * sysdeps/x86/link_map.h (l_cet): Expand to 3 bits, Add + lc_unknown. + +2018-11-05 Andreas Schwab + + [BZ #22927] + * resolv/gai_misc.c (__gai_enqueue_request): Don't crash if + creating the first helper thread failed. + +2018-10-23 Adhemerval Zanella + + [BZ #23709] + * sysdeps/x86/cpu-features.c (init_cpu_features): Set TSX bits + independently of other flags. + +2018-10-30 Florian Weimer + + * stdlib/tst-strtod-overflow.c (do_test): Switch to + support_blob_repeat. + +2018-10-30 Florian Weimer + + * support/blob_repeat.c (allocate_big): Call mkstemp directly. + +2018-10-30 Florian Weimer + + * stdlib/test-bz22786.c (do_test): Additional free calls to avoid + memory leaks. + +2018-10-30 Florian Weimer + + Avoid spurious test failures in stdlib/test-bz22786. + * support/Makefile (libsupport-routines): Add blob_repeat. + (tests): Add tst-support_blob_repeat. + * support/blob_repeat.h: New file. + * support/blob_repeat.c: Likewise. + * support/tst-support_blob_repeat.c: Likewise. + * stdlib/test-bz22786.c (do_test): Replace malloc and memset with + support_blob_repeat_allocate. + +2018-08-30 Stefan Liebler + + * stdlib/test-bz22786.c (do_test): Return EXIT_UNSUPPORTED + if malloc fails. + +2018-08-24 Paul Pluzhnikov + + [BZ #23400] + * stdlib/test-bz22786.c (do_test): Fix undefined behavior, don't + create temporary files in source tree. + +2018-10-26 Szabolcs Nagy + + [BZ #23822] + * sysdeps/ia64/fpu/e_exp2f.S (exp2f): Use WEAK_LIBM_ENTRY. + * sysdeps/ia64/fpu/e_log2f.S (log2f): Likewise. + * sysdeps/ia64/fpu/e_exp2f.S (powf): Likewise. + +2018-10-25 Florian Weimer + + [BZ #23562] + [BZ #23821] + XFAIL siginfo_t si_band conform test on sparc64. + * sysdeps/unix/sysv/linux/sparc/bits/siginfo-arch.h + (__SI_BAND_TYPE): Only override long int default type on sparc64. + * sysdeps/unix/sysv/linux/sparc/sparc64/Makefile + (conformtest-xfail-conds): Add sparc64-linux. + * conform/data/signal.h-data (siginfo_t): XFAIL si_band test on + sparc64. + * conform/data/sys/wait.h-data (siginfo_t): Likewise. + +2018-10-19 Ilya Yu. Malakhov + + [BZ #23562] + * sysdeps/unix/sysv/linux/bits/types/siginfo_t.h + (struct siginfo_t): Use correct type for si_band. + +2018-10-17 Stefan Liebler + + [BZ #23275] + * nptl/tst-mutex10.c: New File. + * nptl/Makefile (tests): Add tst-mutex10. + (tst-mutex10-ENV): New variable. + * sysdeps/unix/sysv/linux/s390/force-elision.h: (FORCE_ELISION): + Ensure that elision path is used if elision is available. + * sysdeps/unix/sysv/linux/powerpc/force-elision.h (FORCE_ELISION): + Likewise. + * sysdeps/unix/sysv/linux/x86/force-elision.h: (FORCE_ELISION): + Likewise. + * nptl/pthreadP.h (PTHREAD_MUTEX_TYPE, PTHREAD_MUTEX_TYPE_ELISION) + (PTHREAD_MUTEX_PSHARED): Use atomic_load_relaxed. + * nptl/pthread_mutex_consistent.c (pthread_mutex_consistent): Likewise. + * nptl/pthread_mutex_getprioceiling.c (pthread_mutex_getprioceiling): + Likewise. + * nptl/pthread_mutex_lock.c (__pthread_mutex_lock_full) + (__pthread_mutex_cond_lock_adjust): Likewise. + * nptl/pthread_mutex_setprioceiling.c (pthread_mutex_setprioceiling): + Likewise. + * nptl/pthread_mutex_timedlock.c (__pthread_mutex_timedlock): Likewise. + * nptl/pthread_mutex_trylock.c (__pthread_mutex_trylock): Likewise. + * nptl/pthread_mutex_unlock.c (__pthread_mutex_unlock_full): Likewise. + * sysdeps/nptl/bits/thread-shared-types.h (struct __pthread_mutex_s): + Add comments. + * nptl/pthread_mutex_destroy.c (__pthread_mutex_destroy): + Use atomic_load_relaxed and atomic_store_relaxed. + * nptl/pthread_mutex_init.c (__pthread_mutex_init): + Use atomic_store_relaxed. + +2018-10-09 H.J. Lu + + [BZ #23716] + * sysdeps/i386/dl-cet.c: Removed. + * sysdeps/i386/dl-machine.h (_dl_runtime_resolve_shstk): New + prototype. + (_dl_runtime_profile_shstk): Likewise. + (elf_machine_runtime_setup): Use _dl_runtime_profile_shstk or + _dl_runtime_resolve_shstk if SHSTK is enabled by kernel. + +2018-10-09 Rafal Luzynski + + [BZ #20209] + * localedata/locales/kl_GL: (abday): Fix spelling of Sun (Sunday), + should be "sap" rather than "sab". + (day): Fix spelling of Sunday, should be "sapaat" rather than + "sabaat". + +2018-09-28 Adhemerval Zanella + + [BZ #23579] + * misc/tst-preadvwritev2-common.c (do_test_with_invalid_fd, + do_test_with_invalid_iov): New tests. + * misc/tst-preadvwritev2.c, misc/tst-preadvwritev64v2.c (do_test): + Call do_test_with_invalid_fd and do_test_with_invalid_iov. + * sysdeps/unix/sysv/linux/preadv2.c (preadv2): Use fallback code iff + errno is ENOSYS. + * sysdeps/unix/sysv/linux/preadv64v2.c (preadv64v2): Likewise. + * sysdeps/unix/sysv/linux/pwritev2.c (pwritev2): Likewise. + * sysdeps/unix/sysv/linux/pwritev64v2.c (pwritev64v2): Likewise. + * NEWS: Add bug fixed. + +2018-09-27 Andreas Schwab + + [BZ #23717] + * stdlib/tst-setcontext9.c (f1a): Make st2 static. + (do_test): Make st1 static. + +2018-09-21 H.J. Lu + Xuepeng Guo + + [BZ #23606] + * sysdeps/i386/start.S: Include + (_start): Use ENTRY/END to insert ENDBR32 at entry when CET is + enabled. Add cfi_undefined (eip). + +2018-09-19 Wilco Dijkstra + + [BZ #23637] + * string/test-strstr.c (pr23637): New function. + (test_main): Add tests with longer needles. + * string/strcasestr.c (AVAILABLE): Fix readahead distance. + * string/strstr.c (AVAILABLE): Likewise. + +2018-09-19 Carlos O'Donell + + * stdlib/tst-setcontext9.c (f1): Rename to... + (f1a): ... this. + (f1b): New function implementing lower half of f1 in alternate stack. + +2018-09-20 Florian Weimer + + * misc/tst-gethostid.c: New file. + * misc/Makefile [$(build-shared)] (tests): Add tst-gethostid. + (tst-gethostid): Link with -ldl. + +2018-09-20 Mingli Yu + + * sysdeps/unix/sysv/linux/gethostid.c (gethostid): Check for NULL + value from gethostbyname_r. + +2018-09-06 Stefan Liebler + + * sysdeps/unix/sysv/linux/spawni.c (maybe_script_execute): + Increment size of new_argv by one. + +2018-08-28 Florian Weimer + + [BZ #23578] + * posix/tst-regcomp-truncated.c: New file. + * posix/Makefile (tests): Add it. + (tst-regcomp-truncated.out): Depend on generated locales. + +2018-08-25 Paul Eggert + + [BZ #23578] + regex: fix uninitialized memory access + I introduced this bug into gnulib in commit + 8335a4d6c7b4448cd0bcb6d0bebf1d456bcfdb17 dated 2006-04-10; + eventually it was merged into glibc. The bug was found by + project-repo and reported here: + https://lists.gnu.org/r/sed-devel/2018-08/msg00017.html + Diagnosis and draft fix reported by Assaf Gordon here: + https://lists.gnu.org/r/bug-gnulib/2018-08/msg00071.html + https://lists.gnu.org/r/bug-gnulib/2018-08/msg00142.html + * posix/regex_internal.c (build_wcs_upper_buffer): + Fix bug when mbrtowc returns 0. + +2018-08-27 Martin Kuchta + Torvald Riegel + + [BZ #23538] + * nptl/pthread_cond_common.c (__condvar_quiesce_and_switch_g1): + Update r to include the set wake-request flag if waiters are + remaining after spinning. + +2018-08-03 DJ Delorie + + * sysdeps/riscv/rvf/math_private.h (libc_feholdexcept_setround_riscv): + Move libc_fesetround_riscv after libc_feholdexcept_riscv. + + * sysdeps/riscv/rv64/rvd/libm-test-ulps: Update. + +2018-08-14 Florian Weimer + + [BZ #23521] + [BZ #23522] + * nss/nss_files/files-alias.c (get_next_alias): During :include: + processing, bail out if no room, and close the stream before + returning ERANGE. + * nss/Makefile (tests): Add tst-nss-files-alias-leak. + (tst-nss-files-alias-leak): Link with libdl. + (tst-nss-files-alias-leak.out): Depend on nss_files. + + * nss/tst-nss-files-alias-leak.c: New file. + +2018-08-14 Florian Weimer + + * nscd/nscd_conf.c (nscd_parse_file): Deallocate old storage for + server_user, stat_user. + +2018-08-13 Florian Weimer + + * misc/error.c (error): Add missing va_end call. + (error_at_line): Likewise. + +2018-08-10 Florian Weimer + + [BZ #23497] + * sysdeps/unix/sysv/linux/getdents64.c (handle_overflow): New + function. + (__old_getdents64): Use getdents64. Convert entries without + moving them. + * sysdeps/unix/sysv/linux/tst-readdir64-compat.c: New file. + * sysdeps/unix/sysv/linux/Makefile (tests-internal): Add + tst-readdir64-compat. + +2018-08-08 Samuel Thibault + + * htl/Versions (__pthread_getspecific, __pthread_setspecific): Add + symbols. + * sysdeps/htl/pthreadP.h [IS_IN (libpthread)] (__pthread_getspecific, + __pthread_setspecific): Add hidden proto. + * sysdeps/htl/pt-getspecific.c (__pthread_getspecific): Add hidden def. + * sysdeps/htl/pt-setspecific.c (__pthread_setspecific): Add hidden def. + 2018-08-01 Carlos O'Donel * version.h (RELEASE): Set to "stable". diff --git a/Makeconfig b/Makeconfig index 608ffe648c..f5e81bdf5d 100644 --- a/Makeconfig +++ b/Makeconfig @@ -831,8 +831,10 @@ endif # disable any optimization that assume default rounding mode. +math-flags = -frounding-math -# Build libc/libm using -fno-math-errno, but run testsuite with -fmath-errno. -+extra-math-flags = $(if $(filter libnldbl nonlib testsuite,$(in-module)),-fmath-errno,-fno-math-errno) +# Logically only "libnldbl", "nonlib" and "testsuite" should be using +# -fno-math-errno. However due to GCC bug #88576, only "libm" can use +# -fno-math-errno. ++extra-math-flags = $(if $(filter libm,$(in-module)),-fno-math-errno,-fmath-errno) # We might want to compile with some stack-protection flag. ifneq ($(stack-protector),) diff --git a/NEWS b/NEWS index 154ab22d7c..9c2c37652f 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,87 @@ See the end for copying conditions. Please send GNU C library bug reports via using `glibc' in the "product" field. +Version 2.28.1 + +Major new features: + +* The entry for the new Japanese era has been added for ja_JP locale. + +Deprecated and removed features, and other changes affecting compatibility: + +* For powercp64le ABI, Transactional Lock Elision is now enabled iff kernel + indicates that it will abort the transaction prior to entering the kernel + (PPC_FEATURE2_HTM_NOSC on hwcap2). On older kernels the transaction is + suspended, and this caused some undefined side-effects issues by aborting + transactions manually. Glibc avoided it by abort transactions manually on + each syscall, but it lead to performance issues on newer kernels where the + HTM state is saved and restore lazily (the state being saved even when the + process actually does not use HTM). + +The following bugs are resolved with this release: + + [18035] Fix pldd hang + [19444] build failures with -O1 due to -Wmaybe-uninitialized + [20018] getaddrinfo should reject IP addresses with trailing characters + [20209] localedata: Spelling mistake for Sunday in Greenlandic kl_GL + [22927] libanl: properly cleanup if first helper thread creation failed + [23400] stdlib/test-bz22786.c creates temporary files in glibc source tree + [23497] readdir64@GLIBC_2.1 cannot parse the kernel directory stream + [23509] CET enabled glibc is incompatible with the older linker + [23521] nss_files aliases database file stream leak + [23538] pthread_cond_broadcast: Fix waiters-after-spinning case + [23562] signal: Use correct type for si_band in siginfo_t + [23578] regex: Fix memory overread in re_compile_pattern + [23579] libc: Errors misreported in preadv2 + [23606] Missing ENDBR32 in sysdeps/i386/start.S + [23614] powerpc: missing CFI register information in __mpn_* functions + [23679] gethostid: Missing NULL check for gethostbyname_r result + [23709] Fix CPU string flags for Haswell-type CPUs + [23717] Fix stack overflow in stdlib/tst-setcontext9 + [23821] si_band in siginfo_t has wrong type long int on sparc64 + [23822] ia64 static libm.a is missing exp2f, log2f and powf symbols + [23864] libc: [riscv] missing kernel-features.h undefines + [23844] pthread_rwlock_trywrlock results in hang + [23927] Linux if_nametoindex() does not close descriptor (CVE-2018-19591) + [23972] __old_getdents64 uses wrong d_off value on overflow + [24018] gettext may return NULL + [24022] riscv may lack + [24024] strerror() might set errno to ENOMEM due to -fno-math-error + [24027] malloc: Integer overflow in realloc + [24034] tst-cancel21-static fails with SIGBUS on pre-ARMv7 when using GCC 8 + [24040] riscv64: unterminated call chain in __thread_start + [24097] Can't use 64-bit register for size_t in assembly codes for x32 (CVE-2019-6488) + [24155] x32 memcmp can treat positive length as 0 (if sign bit in RDX is set) (CVE-2019-7309) + [24161] __run_fork_handlers self-deadlocks in malloc/tst-mallocfork2 + +Security related changes: + + CVE-2018-19591: A file descriptor leak in if_nametoindex can lead to a + denial of service due to resource exhaustion when processing getaddrinfo + calls with crafted host names. Reported by Guido Vranken. + + CVE-2019-6488: On x32, the size_t parameter may be passed in the lower + 32 bits of a 64-bit register with with non-zero upper 32 bit. When it + happened, accessing the 32-bit size_t value as the full 64-bit register + in the assembly string/memory functions would cause a buffer overflow. + Reported by H.J. Lu. + + CVE-2019-7309: x86-64 memcmp used signed Jcc instructions to check + size. For x86-64, memcmp on an object size larger than SSIZE_MAX + has undefined behavior. On x32, the size_t argument may be passed + in the lower 32 bits of the 64-bit RDX register with non-zero upper + 32 bits. When it happened with the sign bit of RDX register set, + memcmp gave the wrong result since it treated the size argument as + zero. Reported by H.J. Lu. + + CVE-2016-10739: The getaddrinfo function could successfully parse IPv4 + addresses with arbitrary trailing characters, potentially leading to data + or command injection issues in applications. + + CVE-2019-9169: Attempted case-insensitive regular-expression match + via proceed_next_node in posix/regexec.c leads to heap-based buffer + over-read. Reported by Hongxu Chen. + Version 2.28 Major new features: @@ -422,6 +503,8 @@ The following bugs are resolved with this release: [23459] libc: COMMON_CPUID_INDEX_80000001 isn't populated for Intel processors [23467] dynamic-link: x86/CET: A property note parser bug + [24112] network: Do not send DNS queries for non-host names (where all + answers will be rejected) Version 2.27 diff --git a/conform/data/signal.h-data b/conform/data/signal.h-data index 11e54adb04..674e5793db 100644 --- a/conform/data/signal.h-data +++ b/conform/data/signal.h-data @@ -172,7 +172,8 @@ element siginfo_t pid_t si_pid element siginfo_t uid_t si_uid element siginfo_t {void*} si_addr element siginfo_t int si_status -element siginfo_t long si_band +// Bug 23821: si_band has type int on sparc64. +xfail[sparc64-linux]-element siginfo_t long si_band # endif # ifndef XPG42 element siginfo_t {union sigval} si_value diff --git a/conform/data/sys/wait.h-data b/conform/data/sys/wait.h-data index ed3869b34f..c0761424da 100644 --- a/conform/data/sys/wait.h-data +++ b/conform/data/sys/wait.h-data @@ -46,7 +46,8 @@ element siginfo_t pid_t si_pid element siginfo_t uid_t si_uid element siginfo_t {void*} si_addr element siginfo_t int si_status -element siginfo_t long si_band +// Bug 23821: si_band has type int on sparc64. +xfail[sparc64-linux]-element siginfo_t long si_band # ifndef XPG42 element siginfo_t {union sigval} si_value # endif diff --git a/dlfcn/dlerror.c b/dlfcn/dlerror.c index 33574faab6..96bf925333 100644 --- a/dlfcn/dlerror.c +++ b/dlfcn/dlerror.c @@ -198,7 +198,10 @@ check_free (struct dl_action_result *rec) Dl_info info; if (_dl_addr (check_free, &info, &map, NULL) != 0 && map->l_ns == 0) #endif - free ((char *) rec->errstring); + { + free ((char *) rec->errstring); + rec->errstring = NULL; + } } } diff --git a/elf/Makefile b/elf/Makefile index cd0771307f..6027926bd1 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -186,7 +186,8 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ tst-tlsalign tst-tlsalign-extern tst-nodelete-opened \ tst-nodelete2 tst-audit11 tst-audit12 tst-dlsym-error tst-noload \ tst-latepthread tst-tls-manydynamic tst-nodelete-dlclose \ - tst-debug1 tst-main1 tst-absolute-sym tst-absolute-zero tst-big-note + tst-debug1 tst-main1 tst-absolute-sym tst-absolute-zero tst-big-note \ + tst-unwind-main # reldep9 tests-internal += loadtest unload unload2 circleload1 \ neededtest neededtest2 neededtest3 neededtest4 \ @@ -1484,3 +1485,5 @@ tst-libc_dlvsym-static-ENV = \ $(objpfx)tst-libc_dlvsym-static.out: $(objpfx)tst-libc_dlvsym-dso.so $(objpfx)tst-big-note: $(objpfx)tst-big-note-lib.so + +CFLAGS-tst-unwind-main.c += -funwind-tables -DUSE_PTHREADS=0 diff --git a/elf/dl-runtime.c b/elf/dl-runtime.c index 63bbc89776..3d2f4a7a76 100644 --- a/elf/dl-runtime.c +++ b/elf/dl-runtime.c @@ -183,10 +183,36 @@ _dl_profile_fixup ( /* This is the address in the array where we store the result of previous relocations. */ struct reloc_result *reloc_result = &l->l_reloc_result[reloc_index]; - DL_FIXUP_VALUE_TYPE *resultp = &reloc_result->addr; - DL_FIXUP_VALUE_TYPE value = *resultp; - if (DL_FIXUP_VALUE_CODE_ADDR (value) == 0) + /* CONCURRENCY NOTES: + + Multiple threads may be calling the same PLT sequence and with + LD_AUDIT enabled they will be calling into _dl_profile_fixup to + update the reloc_result with the result of the lazy resolution. + The reloc_result guard variable is reloc_init, and we use + acquire/release loads and store to it to ensure that the results of + the structure are consistent with the loaded value of the guard. + This does not fix all of the data races that occur when two or more + threads read reloc_result->reloc_init with a value of zero and read + and write to that reloc_result concurrently. The expectation is + generally that while this is a data race it works because the + threads write the same values. Until the data races are fixed + there is a potential for problems to arise from these data races. + The reloc result updates should happen in parallel but there should + be an atomic RMW which does the final update to the real result + entry (see bug 23790). + + The following code uses reloc_result->init set to 0 to indicate if it is + the first time this object is being relocated, otherwise 1 which + indicates the object has already been relocated. + + Reading/Writing from/to reloc_result->reloc_init must not happen + before previous writes to reloc_result complete as they could + end-up with an incomplete struct. */ + DL_FIXUP_VALUE_TYPE value; + unsigned int init = atomic_load_acquire (&reloc_result->init); + + if (init == 0) { /* This is the first time we have to relocate this object. */ const ElfW(Sym) *const symtab @@ -346,19 +372,31 @@ _dl_profile_fixup ( /* Store the result for later runs. */ if (__glibc_likely (! GLRO(dl_bind_not))) - *resultp = value; + { + reloc_result->addr = value; + /* Guarantee all previous writes complete before + init is updated. See CONCURRENCY NOTES earlier */ + atomic_store_release (&reloc_result->init, 1); + } + init = 1; } + else + value = reloc_result->addr; /* By default we do not call the pltexit function. */ long int framesize = -1; + #ifdef SHARED /* Auditing checkpoint: report the PLT entering and allow the auditors to change the value. */ - if (DL_FIXUP_VALUE_CODE_ADDR (value) != 0 && GLRO(dl_naudit) > 0 + if (GLRO(dl_naudit) > 0 /* Don't do anything if no auditor wants to intercept this call. */ && (reloc_result->enterexit & LA_SYMB_NOPLTENTER) == 0) { + /* Sanity check: DL_FIXUP_VALUE_CODE_ADDR (value) should have been + initialized earlier in this function or in another thread. */ + assert (DL_FIXUP_VALUE_CODE_ADDR (value) != 0); ElfW(Sym) *defsym = ((ElfW(Sym) *) D_PTR (reloc_result->bound, l_info[DT_SYMTAB]) + reloc_result->boundndx); diff --git a/elf/pldd-xx.c b/elf/pldd-xx.c index 2823dea662..f818d98582 100644 --- a/elf/pldd-xx.c +++ b/elf/pldd-xx.c @@ -23,10 +23,6 @@ #define EW_(e, w, t) EW__(e, w, _##t) #define EW__(e, w, t) e##w##t -#define pldd_assert(name, exp) \ - typedef int __assert_##name[((exp) != 0) - 1] - - struct E(link_map) { EW(Addr) l_addr; @@ -39,12 +35,12 @@ struct E(link_map) EW(Addr) l_libname; }; #if CLASS == __ELF_NATIVE_CLASS -pldd_assert (l_addr, (offsetof (struct link_map, l_addr) - == offsetof (struct E(link_map), l_addr))); -pldd_assert (l_name, (offsetof (struct link_map, l_name) - == offsetof (struct E(link_map), l_name))); -pldd_assert (l_next, (offsetof (struct link_map, l_next) - == offsetof (struct E(link_map), l_next))); +_Static_assert (offsetof (struct link_map, l_addr) + == offsetof (struct E(link_map), l_addr), "l_addr"); +_Static_assert (offsetof (struct link_map, l_name) + == offsetof (struct E(link_map), l_name), "l_name"); +_Static_assert (offsetof (struct link_map, l_next) + == offsetof (struct E(link_map), l_next), "l_next"); #endif @@ -54,10 +50,10 @@ struct E(libname_list) EW(Addr) next; }; #if CLASS == __ELF_NATIVE_CLASS -pldd_assert (name, (offsetof (struct libname_list, name) - == offsetof (struct E(libname_list), name))); -pldd_assert (next, (offsetof (struct libname_list, next) - == offsetof (struct E(libname_list), next))); +_Static_assert (offsetof (struct libname_list, name) + == offsetof (struct E(libname_list), name), "name"); +_Static_assert (offsetof (struct libname_list, next) + == offsetof (struct E(libname_list), next), "next"); #endif struct E(r_debug) @@ -69,16 +65,17 @@ struct E(r_debug) EW(Addr) r_map; }; #if CLASS == __ELF_NATIVE_CLASS -pldd_assert (r_version, (offsetof (struct r_debug, r_version) - == offsetof (struct E(r_debug), r_version))); -pldd_assert (r_map, (offsetof (struct r_debug, r_map) - == offsetof (struct E(r_debug), r_map))); +_Static_assert (offsetof (struct r_debug, r_version) + == offsetof (struct E(r_debug), r_version), "r_version"); +_Static_assert (offsetof (struct r_debug, r_map) + == offsetof (struct E(r_debug), r_map), "r_map"); #endif static int -E(find_maps) (pid_t pid, void *auxv, size_t auxv_size) +E(find_maps) (const char *exe, int memfd, pid_t pid, void *auxv, + size_t auxv_size) { EW(Addr) phdr = 0; unsigned int phnum = 0; @@ -104,12 +101,9 @@ E(find_maps) (pid_t pid, void *auxv, size_t auxv_size) if (phdr == 0 || phnum == 0 || phent == 0) error (EXIT_FAILURE, 0, gettext ("cannot find program header of process")); - EW(Phdr) *p = alloca (phnum * phent); - if (pread64 (memfd, p, phnum * phent, phdr) != phnum * phent) - { - error (0, 0, gettext ("cannot read program header")); - return EXIT_FAILURE; - } + EW(Phdr) *p = xmalloc (phnum * phent); + if (pread (memfd, p, phnum * phent, phdr) != phnum * phent) + error (EXIT_FAILURE, 0, gettext ("cannot read program header")); /* Determine the load offset. We need this for interpreting the other program header entries so we do this in a separate loop. @@ -129,24 +123,18 @@ E(find_maps) (pid_t pid, void *auxv, size_t auxv_size) if (p[i].p_type == PT_DYNAMIC) { EW(Dyn) *dyn = xmalloc (p[i].p_filesz); - if (pread64 (memfd, dyn, p[i].p_filesz, offset + p[i].p_vaddr) + if (pread (memfd, dyn, p[i].p_filesz, offset + p[i].p_vaddr) != p[i].p_filesz) - { - error (0, 0, gettext ("cannot read dynamic section")); - return EXIT_FAILURE; - } + error (EXIT_FAILURE, 0, gettext ("cannot read dynamic section")); /* Search for the DT_DEBUG entry. */ for (unsigned int j = 0; j < p[i].p_filesz / sizeof (EW(Dyn)); ++j) if (dyn[j].d_tag == DT_DEBUG && dyn[j].d_un.d_ptr != 0) { struct E(r_debug) r; - if (pread64 (memfd, &r, sizeof (r), dyn[j].d_un.d_ptr) + if (pread (memfd, &r, sizeof (r), dyn[j].d_un.d_ptr) != sizeof (r)) - { - error (0, 0, gettext ("cannot read r_debug")); - return EXIT_FAILURE; - } + error (EXIT_FAILURE, 0, gettext ("cannot read r_debug")); if (r.r_map != 0) { @@ -160,13 +148,10 @@ E(find_maps) (pid_t pid, void *auxv, size_t auxv_size) } else if (p[i].p_type == PT_INTERP) { - interp = alloca (p[i].p_filesz); - if (pread64 (memfd, interp, p[i].p_filesz, offset + p[i].p_vaddr) + interp = xmalloc (p[i].p_filesz); + if (pread (memfd, interp, p[i].p_filesz, offset + p[i].p_vaddr) != p[i].p_filesz) - { - error (0, 0, gettext ("cannot read program interpreter")); - return EXIT_FAILURE; - } + error (EXIT_FAILURE, 0, gettext ("cannot read program interpreter")); } if (list == 0) @@ -174,14 +159,16 @@ E(find_maps) (pid_t pid, void *auxv, size_t auxv_size) if (interp == NULL) { // XXX check whether the executable itself is the loader - return EXIT_FAILURE; + exit (EXIT_FAILURE); } // XXX perhaps try finding ld.so and _r_debug in it - - return EXIT_FAILURE; + exit (EXIT_FAILURE); } + free (p); + free (interp); + /* Print the PID and program name first. */ printf ("%lu:\t%s\n", (unsigned long int) pid, exe); @@ -192,47 +179,27 @@ E(find_maps) (pid_t pid, void *auxv, size_t auxv_size) do { struct E(link_map) m; - if (pread64 (memfd, &m, sizeof (m), list) != sizeof (m)) - { - error (0, 0, gettext ("cannot read link map")); - status = EXIT_FAILURE; - goto out; - } + if (pread (memfd, &m, sizeof (m), list) != sizeof (m)) + error (EXIT_FAILURE, 0, gettext ("cannot read link map")); EW(Addr) name_offset = m.l_name; - again: while (1) { - ssize_t n = pread64 (memfd, tmpbuf.data, tmpbuf.length, name_offset); + ssize_t n = pread (memfd, tmpbuf.data, tmpbuf.length, name_offset); if (n == -1) - { - error (0, 0, gettext ("cannot read object name")); - status = EXIT_FAILURE; - goto out; - } + error (EXIT_FAILURE, 0, gettext ("cannot read object name")); if (memchr (tmpbuf.data, '\0', n) != NULL) break; if (!scratch_buffer_grow (&tmpbuf)) - { - error (0, 0, gettext ("cannot allocate buffer for object name")); - status = EXIT_FAILURE; - goto out; - } + error (EXIT_FAILURE, 0, + gettext ("cannot allocate buffer for object name")); } - if (((char *)tmpbuf.data)[0] == '\0' && name_offset == m.l_name - && m.l_libname != 0) - { - /* Try the l_libname element. */ - struct E(libname_list) ln; - if (pread64 (memfd, &ln, sizeof (ln), m.l_libname) == sizeof (ln)) - { - name_offset = ln.name; - goto again; - } - } + /* The m.l_name and m.l_libname.name for loader linkmap points to same + values (since BZ#387 fix). Trying to use l_libname name as the + shared object name might lead to an infinite loop (BZ#18035). */ /* Skip over the executable. */ if (((char *)tmpbuf.data)[0] != '\0') @@ -242,7 +209,6 @@ E(find_maps) (pid_t pid, void *auxv, size_t auxv_size) } while (list != 0); - out: scratch_buffer_free (&tmpbuf); return status; } diff --git a/elf/pldd.c b/elf/pldd.c index b8106fdc33..0bdfff450a 100644 --- a/elf/pldd.c +++ b/elf/pldd.c @@ -17,23 +17,17 @@ License along with the GNU C Library; if not, see . */ -#include +#define _FILE_OFFSET_BITS 64 + #include -#include #include -#include -#include #include #include #include -#include -#include #include #include -#include #include #include -#include #include #include @@ -76,14 +70,9 @@ static struct argp argp = options, parse_opt, args_doc, doc, NULL, more_help, NULL }; -// File descriptor of /proc/*/mem file. -static int memfd; - -/* Name of the executable */ -static char *exe; /* Local functions. */ -static int get_process_info (int dfd, long int pid); +static int get_process_info (const char *exe, int dfd, long int pid); static void wait_for_ptrace_stop (long int pid); @@ -102,8 +91,10 @@ main (int argc, char *argv[]) return 1; } - assert (sizeof (pid_t) == sizeof (int) - || sizeof (pid_t) == sizeof (long int)); + _Static_assert (sizeof (pid_t) == sizeof (int) + || sizeof (pid_t) == sizeof (long int), + "sizeof (pid_t) != sizeof (int) or sizeof (long int)"); + char *endp; errno = 0; long int pid = strtol (argv[remaining], &endp, 10); @@ -119,25 +110,24 @@ main (int argc, char *argv[]) if (dfd == -1) error (EXIT_FAILURE, errno, gettext ("cannot open %s"), buf); - struct scratch_buffer exebuf; - scratch_buffer_init (&exebuf); + /* Name of the executable */ + struct scratch_buffer exe; + scratch_buffer_init (&exe); ssize_t nexe; while ((nexe = readlinkat (dfd, "exe", - exebuf.data, exebuf.length)) == exebuf.length) + exe.data, exe.length)) == exe.length) { - if (!scratch_buffer_grow (&exebuf)) + if (!scratch_buffer_grow (&exe)) { nexe = -1; break; } } if (nexe == -1) - exe = (char *) ""; + /* Default stack allocation is at least 1024. */ + snprintf (exe.data, exe.length, ""); else - { - exe = exebuf.data; - exe[nexe] = '\0'; - } + ((char*)exe.data)[nexe] = '\0'; /* Stop all threads since otherwise the list of loaded modules might change while we are reading it. */ @@ -155,8 +145,8 @@ main (int argc, char *argv[]) error (EXIT_FAILURE, errno, gettext ("cannot prepare reading %s/task"), buf); - struct dirent64 *d; - while ((d = readdir64 (dir)) != NULL) + struct dirent *d; + while ((d = readdir (dir)) != NULL) { if (! isdigit (d->d_name[0])) continue; @@ -182,7 +172,7 @@ main (int argc, char *argv[]) wait_for_ptrace_stop (tid); - struct thread_list *newp = alloca (sizeof (*newp)); + struct thread_list *newp = xmalloc (sizeof (*newp)); newp->tid = tid; newp->next = thread_list; thread_list = newp; @@ -190,17 +180,22 @@ main (int argc, char *argv[]) closedir (dir); - int status = get_process_info (dfd, pid); + if (thread_list == NULL) + error (EXIT_FAILURE, 0, gettext ("no valid %s/task entries"), buf); + + int status = get_process_info (exe.data, dfd, pid); - assert (thread_list != NULL); do { ptrace (PTRACE_DETACH, thread_list->tid, NULL, NULL); + struct thread_list *prev = thread_list; thread_list = thread_list->next; + free (prev); } while (thread_list != NULL); close (dfd); + scratch_buffer_free (&exe); return status; } @@ -281,9 +276,10 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ static int -get_process_info (int dfd, long int pid) +get_process_info (const char *exe, int dfd, long int pid) { - memfd = openat (dfd, "mem", O_RDONLY); + /* File descriptor of /proc//mem file. */ + int memfd = openat (dfd, "mem", O_RDONLY); if (memfd == -1) goto no_info; @@ -333,9 +329,9 @@ get_process_info (int dfd, long int pid) int retval; if (e_ident[EI_CLASS] == ELFCLASS32) - retval = find_maps32 (pid, auxv, auxv_size); + retval = find_maps32 (exe, memfd, pid, auxv, auxv_size); else - retval = find_maps64 (pid, auxv, auxv_size); + retval = find_maps64 (exe, memfd, pid, auxv, auxv_size); free (auxv); close (memfd); diff --git a/elf/tst-unwind-main.c b/elf/tst-unwind-main.c new file mode 100644 index 0000000000..7c20f04743 --- /dev/null +++ b/elf/tst-unwind-main.c @@ -0,0 +1,60 @@ +/* Test unwinding through main. + 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 + +#if USE_PTHREADS +# include +# include +#endif + +static _Unwind_Reason_Code +callback (struct _Unwind_Context *ctx, void *arg) +{ + return _URC_NO_REASON; +} + +static void * +func (void *a) +{ + /* Arrange for this test to be killed if _Unwind_Backtrace runs into an + endless loop. We cannot use the test driver because the complete + call chain needs to be compiled with -funwind-tables so that + _Unwind_Backtrace is able to reach the start routine. */ + alarm (DEFAULT_TIMEOUT); + _Unwind_Backtrace (callback, 0); + return a; +} + +int +main (void) +{ +#if USE_PTHREADS + pthread_t thr; + int rc = pthread_create (&thr, NULL, &func, NULL); + if (rc) + error (1, rc, "pthread_create"); + rc = pthread_join (thr, NULL); + if (rc) + error (1, rc, "pthread_join"); +#else + func (NULL); +#endif +} diff --git a/grp/initgroups.c b/grp/initgroups.c index f056fbf5aa..93e7f5814d 100644 --- a/grp/initgroups.c +++ b/grp/initgroups.c @@ -128,7 +128,7 @@ internal_getgrouplist (const char *user, gid_t group, long int *size, /* This is really only for debugging. */ if (NSS_STATUS_TRYAGAIN > status || status > NSS_STATUS_RETURN) - __libc_fatal ("illegal status in internal_getgrouplist"); + __libc_fatal ("Illegal status in internal_getgrouplist.\n"); /* For compatibility reason we will continue to look for more entries using the next service even though data has already diff --git a/htl/Versions b/htl/Versions index 6a63a1b8a1..c5a616da10 100644 --- a/htl/Versions +++ b/htl/Versions @@ -150,6 +150,8 @@ libpthread { __cthread_keycreate; __cthread_getspecific; __cthread_setspecific; + __pthread_getspecific; + __pthread_setspecific; __pthread_getattr_np; __pthread_attr_getstack; } diff --git a/include/arpa/inet.h b/include/arpa/inet.h index c3f28f2baa..19aec74275 100644 --- a/include/arpa/inet.h +++ b/include/arpa/inet.h @@ -1,10 +1,10 @@ #include #ifndef _ISOMAC -extern int __inet_aton (const char *__cp, struct in_addr *__inp); -libc_hidden_proto (__inet_aton) +/* Variant of inet_aton which rejects trailing garbage. */ +extern int __inet_aton_exact (const char *__cp, struct in_addr *__inp); +libc_hidden_proto (__inet_aton_exact) -libc_hidden_proto (inet_aton) libc_hidden_proto (inet_ntop) libc_hidden_proto (inet_pton) extern __typeof (inet_pton) __inet_pton; diff --git a/include/link.h b/include/link.h index 5924594548..83b1c34b7b 100644 --- a/include/link.h +++ b/include/link.h @@ -216,6 +216,10 @@ struct link_map unsigned int boundndx; uint32_t enterexit; unsigned int flags; + /* CONCURRENCY NOTE: This is used to guard the concurrent initialization + of the relocation result across multiple threads. See the more + detailed notes in elf/dl-runtime.c. */ + unsigned int init; } *l_reloc_result; /* Pointer to the version information if available. */ diff --git a/include/stdio.h b/include/stdio.h index 9162d4e247..7a5c09089f 100644 --- a/include/stdio.h +++ b/include/stdio.h @@ -98,7 +98,8 @@ enum __libc_message_action do_backtrace = 1 << 1 /* Backtrace. */ }; -/* Print out MESSAGE on the error output and abort. */ +/* Print out MESSAGE (which should end with a newline) on the error output + and abort. */ extern void __libc_fatal (const char *__message) __attribute__ ((__noreturn__)); extern void __libc_message (enum __libc_message_action action, diff --git a/inet/Makefile b/inet/Makefile index 09f5ba78fc..7782913b4c 100644 --- a/inet/Makefile +++ b/inet/Makefile @@ -52,7 +52,7 @@ aux := check_pf check_native ifreq tests := htontest test_ifindex tst-ntoa tst-ether_aton tst-network \ tst-gethnm test-ifaddrs bug-if1 test-inet6_opt tst-ether_line \ tst-getni1 tst-getni2 tst-inet6_rth tst-checks tst-checks-posix \ - tst-sockaddr test-hnto-types + tst-sockaddr test-hnto-types tst-if_index-long # tst-deadline must be linked statically so that we can access # internal functions. diff --git a/inet/tst-if_index-long.c b/inet/tst-if_index-long.c new file mode 100644 index 0000000000..3dc74874e5 --- /dev/null +++ b/inet/tst-if_index-long.c @@ -0,0 +1,61 @@ +/* Check for descriptor leak in if_nametoindex with a long interface name. + 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 + . */ + +/* This test checks for a descriptor leak in case of a long interface + name (CVE-2018-19591, bug 23927). */ + +#include +#include +#include +#include +#include +#include +#include + +static int +do_test (void) +{ + struct support_descriptors *descrs = support_descriptors_list (); + + /* Prepare a name which is just as long as required for trigging the + bug. */ + char name[IFNAMSIZ + 1]; + memset (name, 'A', IFNAMSIZ); + name[IFNAMSIZ] = '\0'; + TEST_COMPARE (strlen (name), IFNAMSIZ); + struct ifreq ifr; + TEST_COMPARE (strlen (name), sizeof (ifr.ifr_name)); + + /* Test directly via if_nametoindex. */ + TEST_COMPARE (if_nametoindex (name), 0); + TEST_COMPARE (errno, ENODEV); + support_descriptors_check (descrs); + + /* Same test via getaddrinfo. */ + char *host = xasprintf ("fea0::%%%s", name); + struct addrinfo hints = { .ai_flags = AI_NUMERICHOST, }; + struct addrinfo *ai; + TEST_COMPARE (getaddrinfo (host, NULL, &hints, &ai), EAI_NONAME); + support_descriptors_check (descrs); + + support_descriptors_free (descrs); + + return 0; +} + +#include diff --git a/intl/dcigettext.c b/intl/dcigettext.c index 2a50369948..25f47c5bd3 100644 --- a/intl/dcigettext.c +++ b/intl/dcigettext.c @@ -631,7 +631,7 @@ DCIGETTEXT (const char *domainname, const char *msgid1, const char *msgid2, int ret = __asprintf (&xdirname, "%s/%s", cwd, dirname); free (cwd); if (ret < 0) - return NULL; + goto return_untranslated; dirname = xdirname; } #ifndef IN_LIBGLOCALE diff --git a/libio/tst-readline.c b/libio/tst-readline.c index 9322ef68da..63f5227760 100644 --- a/libio/tst-readline.c +++ b/libio/tst-readline.c @@ -232,5 +232,6 @@ do_test (void) return 0; } +#define TIMEOUT 100 #define PREPARE prepare #include diff --git a/localedata/locales/ja_JP b/localedata/locales/ja_JP index 1fd2fee44b..30190b6248 100644 --- a/localedata/locales/ja_JP +++ b/localedata/locales/ja_JP @@ -14946,7 +14946,9 @@ am_pm "";"" t_fmt_ampm "%p%I%M%S" -era "+:2:1990//01//01:+*::%EC%Ey";/ +era "+:2:2020//01//01:+*::%EC%Ey";/ + "+:1:2019//05//01:2019//12//31::%EC";/ + "+:2:1990//01//01:2019//04//30::%EC%Ey";/ "+:1:1989//01//08:1989//12//31::%EC";/ "+:2:1927//01//01:1989//01//07::%EC%Ey";/ "+:1:1926//12//25:1926//12//31::%EC";/ diff --git a/localedata/locales/kl_GL b/localedata/locales/kl_GL index 5ab14a31aa..5723ce7dcf 100644 --- a/localedata/locales/kl_GL +++ b/localedata/locales/kl_GL @@ -70,11 +70,11 @@ copy "da_DK" END LC_NUMERIC LC_TIME -abday "sab";"ata";/ +abday "sap";"ata";/ "mar";"pin";/ "sis";"tal";/ "arf" -day "sabaat";/ +day "sapaat";/ "ataasinngorneq";/ "marlunngorneq";/ "pingasunngorneq";/ diff --git a/malloc/Makefile b/malloc/Makefile index 7d54bad866..388cf7e9ee 100644 --- a/malloc/Makefile +++ b/malloc/Makefile @@ -38,6 +38,7 @@ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \ tst-malloc_info \ tst-malloc-too-large \ tst-malloc-stats-cancellation \ + tst-tcfree1 tst-tcfree2 tst-tcfree3 \ tests-static := \ tst-interpose-static-nothread \ diff --git a/malloc/malloc.c b/malloc/malloc.c index e247c77b7d..27cf6137c2 100644 --- a/malloc/malloc.c +++ b/malloc/malloc.c @@ -2888,6 +2888,8 @@ mremap_chunk (mchunkptr p, size_t new_size) typedef struct tcache_entry { struct tcache_entry *next; + /* This field exists to detect double frees. */ + struct tcache_perthread_struct *key; } tcache_entry; /* There is one of these for each thread, which contains the @@ -2911,6 +2913,11 @@ tcache_put (mchunkptr chunk, size_t tc_idx) { tcache_entry *e = (tcache_entry *) chunk2mem (chunk); assert (tc_idx < TCACHE_MAX_BINS); + + /* Mark this chunk as "in the tcache" so the test in _int_free will + detect a double free. */ + e->key = tcache; + e->next = tcache->entries[tc_idx]; tcache->entries[tc_idx] = e; ++(tcache->counts[tc_idx]); @@ -2926,6 +2933,7 @@ tcache_get (size_t tc_idx) assert (tcache->entries[tc_idx] > 0); tcache->entries[tc_idx] = e->next; --(tcache->counts[tc_idx]); + e->key = NULL; return (void *) e; } @@ -3716,11 +3724,22 @@ _int_malloc (mstate av, size_t bytes) while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av)) { bck = victim->bk; - if (__builtin_expect (chunksize_nomask (victim) <= 2 * SIZE_SZ, 0) - || __builtin_expect (chunksize_nomask (victim) - > av->system_mem, 0)) - malloc_printerr ("malloc(): memory corruption"); size = chunksize (victim); + mchunkptr next = chunk_at_offset (victim, size); + + if (__glibc_unlikely (size <= 2 * SIZE_SZ) + || __glibc_unlikely (size > av->system_mem)) + malloc_printerr ("malloc(): invalid size (unsorted)"); + if (__glibc_unlikely (chunksize_nomask (next) < 2 * SIZE_SZ) + || __glibc_unlikely (chunksize_nomask (next) > av->system_mem)) + malloc_printerr ("malloc(): invalid next size (unsorted)"); + if (__glibc_unlikely ((prev_size (next) & ~(SIZE_BITS)) != size)) + malloc_printerr ("malloc(): mismatching next->prev_size (unsorted)"); + if (__glibc_unlikely (bck->fd != victim) + || __glibc_unlikely (victim->fd != unsorted_chunks (av))) + malloc_printerr ("malloc(): unsorted double linked list corrupted"); + if (__glibc_unlikely (prev_inuse(next))) + malloc_printerr ("malloc(): invalid next->prev_inuse (unsorted)"); /* If a small request, try to use last remainder if it is the @@ -4076,6 +4095,9 @@ _int_malloc (mstate av, size_t bytes) victim = av->top; size = chunksize (victim); + if (__glibc_unlikely (size > av->system_mem)) + malloc_printerr ("malloc(): corrupted top size"); + if ((unsigned long) (size) >= (unsigned long) (nb + MINSIZE)) { remainder_size = size - nb; @@ -4151,13 +4173,33 @@ _int_free (mstate av, mchunkptr p, int have_lock) #if USE_TCACHE { size_t tc_idx = csize2tidx (size); - - if (tcache - && tc_idx < mp_.tcache_bins - && tcache->counts[tc_idx] < mp_.tcache_count) + if (tcache != NULL && tc_idx < mp_.tcache_bins) { - tcache_put (p, tc_idx); - return; + /* Check to see if it's already in the tcache. */ + tcache_entry *e = (tcache_entry *) chunk2mem (p); + + /* This test succeeds on double free. However, we don't 100% + trust it (it also matches random payload data at a 1 in + 2^ chance), so verify it's not an unlikely + coincidence before aborting. */ + if (__glibc_unlikely (e->key == tcache)) + { + tcache_entry *tmp; + LIBC_PROBE (memory_tcache_double_free, 2, e, tc_idx); + for (tmp = tcache->entries[tc_idx]; + tmp; + tmp = tmp->next) + if (tmp == e) + malloc_printerr ("free(): double free detected in tcache 2"); + /* If we get here, it was a coincidence. We've wasted a + few cycles, but don't abort. */ + } + + if (tcache->counts[tc_idx] < mp_.tcache_count) + { + tcache_put (p, tc_idx); + return; + } } } #endif @@ -4278,6 +4320,8 @@ _int_free (mstate av, mchunkptr p, int have_lock) prevsize = prev_size (p); size += prevsize; p = chunk_at_offset(p, -((long) prevsize)); + if (__glibc_unlikely (chunksize(p) != prevsize)) + malloc_printerr ("corrupted size vs. prev_size while consolidating"); unlink(av, p, bck, fwd); } @@ -4439,6 +4483,8 @@ static void malloc_consolidate(mstate av) prevsize = prev_size (p); size += prevsize; p = chunk_at_offset(p, -((long) prevsize)); + if (__glibc_unlikely (chunksize(p) != prevsize)) + malloc_printerr ("corrupted size vs. prev_size in fastbins"); unlink(av, p, bck, fwd); } @@ -4498,11 +4544,6 @@ _int_realloc(mstate av, mchunkptr oldp, INTERNAL_SIZE_T oldsize, mchunkptr bck; /* misc temp for linking */ mchunkptr fwd; /* misc temp for linking */ - unsigned long copysize; /* bytes to copy */ - unsigned int ncopies; /* INTERNAL_SIZE_T words to copy */ - INTERNAL_SIZE_T* s; /* copy source */ - INTERNAL_SIZE_T* d; /* copy destination */ - /* oldmem size */ if (__builtin_expect (chunksize_nomask (oldp) <= 2 * SIZE_SZ, 0) || __builtin_expect (oldsize >= av->system_mem, 0)) @@ -4570,43 +4611,7 @@ _int_realloc(mstate av, mchunkptr oldp, INTERNAL_SIZE_T oldsize, } else { - /* - Unroll copy of <= 36 bytes (72 if 8byte sizes) - We know that contents have an odd number of - INTERNAL_SIZE_T-sized words; minimally 3. - */ - - copysize = oldsize - SIZE_SZ; - s = (INTERNAL_SIZE_T *) (chunk2mem (oldp)); - d = (INTERNAL_SIZE_T *) (newmem); - ncopies = copysize / sizeof (INTERNAL_SIZE_T); - assert (ncopies >= 3); - - if (ncopies > 9) - memcpy (d, s, copysize); - - else - { - *(d + 0) = *(s + 0); - *(d + 1) = *(s + 1); - *(d + 2) = *(s + 2); - if (ncopies > 4) - { - *(d + 3) = *(s + 3); - *(d + 4) = *(s + 4); - if (ncopies > 6) - { - *(d + 5) = *(s + 5); - *(d + 6) = *(s + 6); - if (ncopies > 8) - { - *(d + 7) = *(s + 7); - *(d + 8) = *(s + 8); - } - } - } - } - + memcpy (newmem, chunk2mem (oldp), oldsize - SIZE_SZ); _int_free (av, oldp, 1); check_inuse_chunk (av, newp); return chunk2mem (newp); diff --git a/malloc/tst-tcfree1.c b/malloc/tst-tcfree1.c new file mode 100644 index 0000000000..bc29375ce7 --- /dev/null +++ b/malloc/tst-tcfree1.c @@ -0,0 +1,42 @@ +/* Test that malloc tcache catches double free. + 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 + +static int +do_test (void) +{ + /* Do one allocation of any size that fits in tcache. */ + char * volatile x = malloc (32); + + free (x); // puts in tcache + free (x); // should abort + + printf("FAIL: tcache double free not detected\n"); + return 1; +} + +#define TEST_FUNCTION do_test +#define EXPECTED_SIGNAL SIGABRT +#include diff --git a/malloc/tst-tcfree2.c b/malloc/tst-tcfree2.c new file mode 100644 index 0000000000..17f06bacd4 --- /dev/null +++ b/malloc/tst-tcfree2.c @@ -0,0 +1,48 @@ +/* Test that malloc tcache catches double free. + 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 + +static int +do_test (void) +{ + char * volatile ptrs[20]; + int i; + + /* Allocate enough small chunks so that when we free them all, the tcache + is full, and the first one we freed is at the end of its linked list. */ +#define COUNT 20 + for (i=0; i diff --git a/malloc/tst-tcfree3.c b/malloc/tst-tcfree3.c new file mode 100644 index 0000000000..016d30ddd8 --- /dev/null +++ b/malloc/tst-tcfree3.c @@ -0,0 +1,56 @@ +/* Test that malloc tcache catches double free. + 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 + +/* Prevent GCC from optimizing away any malloc/free pairs. */ +#pragma GCC optimize ("O0") + +static int +do_test (void) +{ + /* Do two allocation of any size that fit in tcache, and one that + doesn't. */ + int ** volatile a = malloc (32); + int ** volatile b = malloc (32); + /* This is just under the mmap threshold. */ + int ** volatile c = malloc (127 * 1024); + + /* The invalid "tcache bucket" we might dereference will likely end + up somewhere within this memory block, so make all the accidental + "next" pointers cause segfaults. BZ #23907. */ + memset (c, 0xff, 127 * 1024); + + free (a); // puts in tcache + + /* A is now free and contains the key we use to detect in-tcache. + Copy the key to the other chunks. */ + memcpy (b, a, 32); + memcpy (c, a, 32); + + /* This free tests the "are we in the tcache already" loop with a + VALID bin but "coincidental" matching key. */ + free (b); // should NOT abort + /* This free tests the "is it a valid tcache bin" test. */ + free (c); // should NOT abort + + return 0; +} + +#include diff --git a/math/libm-test-fma.inc b/math/libm-test-fma.inc index 5b29fb8201..a7ee409924 100644 --- a/math/libm-test-fma.inc +++ b/math/libm-test-fma.inc @@ -119,32 +119,32 @@ static const struct test_fff_f_data fma_test_data[] = TEST_fff_f (fma, plus_infty, plus_infty, -min_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_fff_f (fma, plus_infty, plus_infty, min_subnorm_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_fff_f (fma, plus_infty, plus_infty, -min_subnorm_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), - TEST_fff_f (fma, plus_infty, plus_infty, max_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), - TEST_fff_f (fma, plus_infty, plus_infty, -max_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_fff_f (fma, plus_infty, plus_infty, max_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|XFAIL_ROUNDING_IBM128_LIBGCC), + TEST_fff_f (fma, plus_infty, plus_infty, -max_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|XFAIL_ROUNDING_IBM128_LIBGCC), TEST_fff_f (fma, plus_infty, minus_infty, plus_zero, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_fff_f (fma, plus_infty, minus_infty, minus_zero, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_fff_f (fma, plus_infty, minus_infty, min_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_fff_f (fma, plus_infty, minus_infty, -min_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_fff_f (fma, plus_infty, minus_infty, min_subnorm_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_fff_f (fma, plus_infty, minus_infty, -min_subnorm_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), - TEST_fff_f (fma, plus_infty, minus_infty, max_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), - TEST_fff_f (fma, plus_infty, minus_infty, -max_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_fff_f (fma, plus_infty, minus_infty, max_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|XFAIL_ROUNDING_IBM128_LIBGCC), + TEST_fff_f (fma, plus_infty, minus_infty, -max_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|XFAIL_ROUNDING_IBM128_LIBGCC), TEST_fff_f (fma, minus_infty, plus_infty, plus_zero, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_fff_f (fma, minus_infty, plus_infty, minus_zero, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_fff_f (fma, minus_infty, plus_infty, min_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_fff_f (fma, minus_infty, plus_infty, -min_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_fff_f (fma, minus_infty, plus_infty, min_subnorm_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_fff_f (fma, minus_infty, plus_infty, -min_subnorm_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), - TEST_fff_f (fma, minus_infty, plus_infty, max_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), - TEST_fff_f (fma, minus_infty, plus_infty, -max_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_fff_f (fma, minus_infty, plus_infty, max_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|XFAIL_ROUNDING_IBM128_LIBGCC), + TEST_fff_f (fma, minus_infty, plus_infty, -max_value, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|XFAIL_ROUNDING_IBM128_LIBGCC), TEST_fff_f (fma, minus_infty, minus_infty, plus_zero, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_fff_f (fma, minus_infty, minus_infty, minus_zero, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_fff_f (fma, minus_infty, minus_infty, min_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_fff_f (fma, minus_infty, minus_infty, -min_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_fff_f (fma, minus_infty, minus_infty, min_subnorm_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), TEST_fff_f (fma, minus_infty, minus_infty, -min_subnorm_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), - TEST_fff_f (fma, minus_infty, minus_infty, max_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), - TEST_fff_f (fma, minus_infty, minus_infty, -max_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED), + TEST_fff_f (fma, minus_infty, minus_infty, max_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|XFAIL_ROUNDING_IBM128_LIBGCC), + TEST_fff_f (fma, minus_infty, minus_infty, -max_value, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|XFAIL_ROUNDING_IBM128_LIBGCC), AUTO_TESTS_fff_f (fma), }; diff --git a/misc/Makefile b/misc/Makefile index b7be2bc19a..c9f81515ac 100644 --- a/misc/Makefile +++ b/misc/Makefile @@ -86,6 +86,11 @@ tests := tst-dirname tst-tsearch tst-fdset tst-efgcvt tst-mntent tst-hsearch \ tst-preadvwritev tst-preadvwritev64 tst-makedev tst-empty \ tst-preadvwritev2 tst-preadvwritev64v2 +# Tests which need libdl. +ifeq (yes,$(build-shared)) +tests += tst-gethostid +endif + tests-internal := tst-atomic tst-atomic-long tst-allocate_once tests-static := tst-empty @@ -145,3 +150,5 @@ tst-allocate_once-ENV = MALLOC_TRACE=$(objpfx)tst-allocate_once.mtrace $(objpfx)tst-allocate_once-mem.out: $(objpfx)tst-allocate_once.out $(common-objpfx)malloc/mtrace $(objpfx)tst-allocate_once.mtrace > $@; \ $(evaluate-test) + +$(objpfx)tst-gethostid: $(libdl) diff --git a/misc/error.c b/misc/error.c index b4e8b6c938..03378e2f2a 100644 --- a/misc/error.c +++ b/misc/error.c @@ -319,6 +319,7 @@ error (int status, int errnum, const char *message, ...) va_start (args, message); error_tail (status, errnum, message, args); + va_end (args); #ifdef _LIBC _IO_funlockfile (stderr); @@ -390,6 +391,7 @@ error_at_line (int status, int errnum, const char *file_name, va_start (args, message); error_tail (status, errnum, message, args); + va_end (args); #ifdef _LIBC _IO_funlockfile (stderr); diff --git a/misc/tst-gethostid.c b/misc/tst-gethostid.c new file mode 100644 index 0000000000..1490aaf3f5 --- /dev/null +++ b/misc/tst-gethostid.c @@ -0,0 +1,108 @@ +/* Basic test for gethostid. + 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 +#include +#include + +/* Initial test is run outside a chroot, to increase the likelihood of + success. */ +static void +outside_chroot (void *closure) +{ + long id = gethostid (); + printf ("info: host ID outside chroot: 0x%lx\n", id); +} + +/* The same, but this time perform a chroot operation. */ +static void +in_chroot (void *closure) +{ + const char *chroot_path = closure; + xchroot (chroot_path); + long id = gethostid (); + printf ("info: host ID in chroot: 0x%lx\n", id); +} + +static int +do_test (void) +{ + support_isolate_in_subprocess (outside_chroot, NULL); + + /* Now run the test inside a chroot. */ + support_become_root (); + if (!support_can_chroot ()) + /* Cannot perform further tests. */ + return 0; + + /* Only use nss_files. */ + __nss_configure_lookup ("hosts", "files"); + + /* Load the DSO outside of the chroot. */ + xdlopen (LIBNSS_FILES_SO, RTLD_LAZY); + + char *chroot_dir = support_create_temp_directory ("tst-gethostid-"); + support_isolate_in_subprocess (in_chroot, chroot_dir); + + /* Tests with /etc/hosts in the chroot. */ + { + char *path = xasprintf ("%s/etc", chroot_dir); + add_temp_file (path); + xmkdir (path, 0777); + free (path); + path = xasprintf ("%s/etc/hosts", chroot_dir); + add_temp_file (path); + + FILE *fp = xfopen (path, "w"); + xfclose (fp); + printf ("info: chroot test with an empty /etc/hosts file\n"); + support_isolate_in_subprocess (in_chroot, chroot_dir); + + char hostname[1024]; + int ret = gethostname (hostname, sizeof (hostname)); + if (ret < 0) + printf ("warning: invalid result from gethostname: %d\n", ret); + else if (strlen (hostname) == 0) + puts ("warning: gethostname returned empty string"); + else + { + printf ("info: chroot test with IPv6 address in /etc/hosts for: %s\n", + hostname); + fp = xfopen (path, "w"); + /* Use an IPv6 address to induce another lookup failure. */ + fprintf (fp, "2001:db8::1 %s\n", hostname); + xfclose (fp); + support_isolate_in_subprocess (in_chroot, chroot_dir); + } + free (path); + } + free (chroot_dir); + + return 0; +} + +#include diff --git a/misc/tst-preadvwritev2-common.c b/misc/tst-preadvwritev2-common.c index f889a21544..50b9da3fea 100644 --- a/misc/tst-preadvwritev2-common.c +++ b/misc/tst-preadvwritev2-common.c @@ -19,9 +19,6 @@ #include #include -static void -do_test_with_invalid_flags (void) -{ #ifndef RWF_HIPRI # define RWF_HIPRI 0 #endif @@ -39,6 +36,68 @@ do_test_with_invalid_flags (void) #endif #define RWF_SUPPORTED (RWF_HIPRI | RWF_DSYNC | RWF_SYNC | RWF_NOWAIT \ | RWF_APPEND) + +static void +do_test_with_invalid_fd (void) +{ + char buf[256]; + struct iovec iov = { buf, sizeof buf }; + + /* Check with flag being 0 to use the fallback code which calls pwritev + or writev. */ + TEST_VERIFY (preadv2 (-1, &iov, 1, -1, 0) == -1); + TEST_COMPARE (errno, EBADF); + TEST_VERIFY (pwritev2 (-1, &iov, 1, -1, 0) == -1); + TEST_COMPARE (errno, EBADF); + + /* Same tests as before but with flags being different than 0. Since + there is no emulation for any flag value, fallback code returns + ENOTSUP. This is different running on a kernel with preadv2/pwritev2 + support, where EBADF is returned). */ + TEST_VERIFY (preadv2 (-1, &iov, 1, 0, RWF_HIPRI) == -1); + TEST_VERIFY (errno == EBADF || errno == ENOTSUP); + TEST_VERIFY (pwritev2 (-1, &iov, 1, 0, RWF_HIPRI) == -1); + TEST_VERIFY (errno == EBADF || errno == ENOTSUP); +} + +static void +do_test_with_invalid_iov (void) +{ + { + char buf[256]; + struct iovec iov; + + iov.iov_base = buf; + iov.iov_len = (size_t)SSIZE_MAX + 1; + + TEST_VERIFY (preadv2 (temp_fd, &iov, 1, 0, 0) == -1); + TEST_COMPARE (errno, EINVAL); + TEST_VERIFY (pwritev2 (temp_fd, &iov, 1, 0, 0) == -1); + TEST_COMPARE (errno, EINVAL); + + /* Same as for invalid file descriptor tests, emulation fallback + first checks for flag value and return ENOTSUP. */ + TEST_VERIFY (preadv2 (temp_fd, &iov, 1, 0, RWF_HIPRI) == -1); + TEST_VERIFY (errno == EINVAL || errno == ENOTSUP); + TEST_VERIFY (pwritev2 (temp_fd, &iov, 1, 0, RWF_HIPRI) == -1); + TEST_VERIFY (errno == EINVAL || errno == ENOTSUP); + } + + { + /* An invalid iovec buffer should trigger an invalid memory access + or an error (Linux for instance returns EFAULT). */ + struct iovec iov[IOV_MAX+1] = { 0 }; + + TEST_VERIFY (preadv2 (temp_fd, iov, IOV_MAX + 1, 0, RWF_HIPRI) == -1); + TEST_VERIFY (errno == EINVAL || errno == ENOTSUP); + TEST_VERIFY (pwritev2 (temp_fd, iov, IOV_MAX + 1, 0, RWF_HIPRI) == -1); + TEST_VERIFY (errno == EINVAL || errno == ENOTSUP); + } +} + +static void +do_test_with_invalid_flags (void) +{ /* Set the next bit from the mask of all supported flags. */ int invalid_flag = RWF_SUPPORTED != 0 ? __builtin_clz (RWF_SUPPORTED) : 2; invalid_flag = 0x1 << ((sizeof (int) * CHAR_BIT) - invalid_flag); diff --git a/misc/tst-preadvwritev2.c b/misc/tst-preadvwritev2.c index be22802dbe..cb58cbe41e 100644 --- a/misc/tst-preadvwritev2.c +++ b/misc/tst-preadvwritev2.c @@ -30,6 +30,8 @@ do_test (void) { do_test_with_invalid_flags (); do_test_without_offset (); + do_test_with_invalid_fd (); + do_test_with_invalid_iov (); return do_test_with_offset (0); } diff --git a/misc/tst-preadvwritev64v2.c b/misc/tst-preadvwritev64v2.c index 8d3cc32b28..6a9de54c78 100644 --- a/misc/tst-preadvwritev64v2.c +++ b/misc/tst-preadvwritev64v2.c @@ -32,6 +32,8 @@ do_test (void) { do_test_with_invalid_flags (); do_test_without_offset (); + do_test_with_invalid_fd (); + do_test_with_invalid_iov (); return do_test_with_offset (0); } diff --git a/nptl/Makefile b/nptl/Makefile index be8066524c..5be7655529 100644 --- a/nptl/Makefile +++ b/nptl/Makefile @@ -241,9 +241,9 @@ LDLIBS-tst-minstack-throw = -lstdc++ tests = tst-attr1 tst-attr2 tst-attr3 tst-default-attr \ tst-mutex1 tst-mutex2 tst-mutex3 tst-mutex4 tst-mutex5 tst-mutex6 \ - tst-mutex7 tst-mutex9 tst-mutex5a tst-mutex7a tst-mutex7robust \ - tst-mutexpi1 tst-mutexpi2 tst-mutexpi3 tst-mutexpi4 tst-mutexpi5 \ - tst-mutexpi5a tst-mutexpi6 tst-mutexpi7 tst-mutexpi7a \ + tst-mutex7 tst-mutex9 tst-mutex10 tst-mutex5a tst-mutex7a \ + tst-mutex7robust tst-mutexpi1 tst-mutexpi2 tst-mutexpi3 tst-mutexpi4 \ + tst-mutexpi5 tst-mutexpi5a tst-mutexpi6 tst-mutexpi7 tst-mutexpi7a \ tst-mutexpi9 \ tst-spin1 tst-spin2 tst-spin3 tst-spin4 \ tst-cond1 tst-cond2 tst-cond3 tst-cond4 tst-cond5 tst-cond6 tst-cond7 \ @@ -318,7 +318,10 @@ tests = tst-attr1 tst-attr2 tst-attr3 tst-default-attr \ tst-minstack-throw \ tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \ tst-cnd-timedwait tst-thrd-detach tst-mtx-basic tst-thrd-sleep \ - tst-mtx-recursive tst-tss-basic tst-call-once tst-mtx-timedlock + tst-mtx-recursive tst-tss-basic tst-call-once tst-mtx-timedlock \ + tst-rwlock-pwn \ + tst-rwlock-tryrdlock-stall tst-rwlock-trywrlock-stall \ + tst-unwind-thread tests-internal := tst-rwlock19 tst-rwlock20 \ tst-sem11 tst-sem12 tst-sem13 \ @@ -382,7 +385,8 @@ tests += tst-cancelx2 tst-cancelx3 tst-cancelx4 tst-cancelx5 \ tst-cleanupx0 tst-cleanupx1 tst-cleanupx2 tst-cleanupx3 tst-cleanupx4 \ tst-oncex3 tst-oncex4 ifeq ($(build-shared),yes) -tests += tst-atfork2 tst-tls4 tst-_res1 tst-fini1 tst-compat-forwarder +tests += tst-atfork2 tst-tls4 tst-_res1 tst-fini1 tst-compat-forwarder \ + tst-audit-threads tests-internal += tst-tls3 tst-tls3-malloc tst-tls5 tst-stackguard1 tests-nolibpthread += tst-fini1 ifeq ($(have-z-execstack),yes) @@ -394,7 +398,8 @@ modules-names = tst-atfork2mod tst-tls3mod tst-tls4moda tst-tls4modb \ tst-tls5mod tst-tls5moda tst-tls5modb tst-tls5modc \ tst-tls5modd tst-tls5mode tst-tls5modf tst-stack4mod \ tst-_res1mod1 tst-_res1mod2 tst-execstack-mod tst-fini1mod \ - tst-join7mod tst-compat-forwarder-mod + tst-join7mod tst-compat-forwarder-mod tst-audit-threads-mod1 \ + tst-audit-threads-mod2 extra-test-objs += $(addsuffix .os,$(strip $(modules-names))) \ tst-cleanup4aux.o tst-cleanupx4aux.o test-extras += tst-cleanup4aux tst-cleanupx4aux @@ -709,6 +714,18 @@ endif $(objpfx)tst-compat-forwarder: $(objpfx)tst-compat-forwarder-mod.so +tst-mutex10-ENV = GLIBC_TUNABLES=glibc.elision.enable=1 + +# Protect against a build using -Wl,-z,now. +LDFLAGS-tst-audit-threads-mod1.so = -Wl,-z,lazy +LDFLAGS-tst-audit-threads-mod2.so = -Wl,-z,lazy +LDFLAGS-tst-audit-threads = -Wl,-z,lazy +$(objpfx)tst-audit-threads: $(objpfx)tst-audit-threads-mod2.so +$(objpfx)tst-audit-threads.out: $(objpfx)tst-audit-threads-mod1.so +tst-audit-threads-ENV = LD_AUDIT=$(objpfx)tst-audit-threads-mod1.so + +CFLAGS-tst-unwind-thread.c += -funwind-tables + # The tests here better do not run in parallel ifneq ($(filter %tests,$(MAKECMDGOALS)),) .NOTPARALLEL: diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h index 13bdb11133..19efe1e35f 100644 --- a/nptl/pthreadP.h +++ b/nptl/pthreadP.h @@ -110,19 +110,23 @@ enum }; #define PTHREAD_MUTEX_PSHARED_BIT 128 +/* See concurrency notes regarding __kind in struct __pthread_mutex_s + in sysdeps/nptl/bits/thread-shared-types.h. */ #define PTHREAD_MUTEX_TYPE(m) \ - ((m)->__data.__kind & 127) + (atomic_load_relaxed (&((m)->__data.__kind)) & 127) /* Don't include NO_ELISION, as that type is always the same as the underlying lock type. */ #define PTHREAD_MUTEX_TYPE_ELISION(m) \ - ((m)->__data.__kind & (127|PTHREAD_MUTEX_ELISION_NP)) + (atomic_load_relaxed (&((m)->__data.__kind)) \ + & (127 | PTHREAD_MUTEX_ELISION_NP)) #if LLL_PRIVATE == 0 && LLL_SHARED == 128 # define PTHREAD_MUTEX_PSHARED(m) \ - ((m)->__data.__kind & 128) + (atomic_load_relaxed (&((m)->__data.__kind)) & 128) #else # define PTHREAD_MUTEX_PSHARED(m) \ - (((m)->__data.__kind & 128) ? LLL_SHARED : LLL_PRIVATE) + ((atomic_load_relaxed (&((m)->__data.__kind)) & 128) \ + ? LLL_SHARED : LLL_PRIVATE) #endif /* The kernel when waking robust mutexes on exit never uses diff --git a/nptl/pthread_cond_common.c b/nptl/pthread_cond_common.c index 8e425eb01e..479e54febb 100644 --- a/nptl/pthread_cond_common.c +++ b/nptl/pthread_cond_common.c @@ -405,8 +405,12 @@ __condvar_quiesce_and_switch_g1 (pthread_cond_t *cond, uint64_t wseq, { /* There is still a waiter after spinning. Set the wake-request flag and block. Relaxed MO is fine because this is just about - this futex word. */ - r = atomic_fetch_or_relaxed (cond->__data.__g_refs + g1, 1); + this futex word. + + Update r to include the set wake-request flag so that the upcoming + futex_wait only blocks if the flag is still set (otherwise, we'd + violate the basic client-side futex protocol). */ + r = atomic_fetch_or_relaxed (cond->__data.__g_refs + g1, 1) | 1; if ((r >> 1) > 0) futex_wait_simple (cond->__data.__g_refs + g1, r, private); diff --git a/nptl/pthread_cond_wait.c b/nptl/pthread_cond_wait.c index 3e11054182..ebf07ca82d 100644 --- a/nptl/pthread_cond_wait.c +++ b/nptl/pthread_cond_wait.c @@ -516,7 +516,7 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex, struct timespec rt; if (__clock_gettime (CLOCK_MONOTONIC, &rt) != 0) __libc_fatal ("clock_gettime does not support " - "CLOCK_MONOTONIC"); + "CLOCK_MONOTONIC\n"); /* Convert the absolute timeout value to a relative timeout. */ rt.tv_sec = abstime->tv_sec - rt.tv_sec; diff --git a/nptl/pthread_mutex_consistent.c b/nptl/pthread_mutex_consistent.c index 85b8e1a6cb..4fbd875430 100644 --- a/nptl/pthread_mutex_consistent.c +++ b/nptl/pthread_mutex_consistent.c @@ -23,8 +23,11 @@ int pthread_mutex_consistent (pthread_mutex_t *mutex) { - /* Test whether this is a robust mutex with a dead owner. */ - if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0 + /* Test whether this is a robust mutex with a dead owner. + See concurrency notes regarding __kind in struct __pthread_mutex_s + in sysdeps/nptl/bits/thread-shared-types.h. */ + if ((atomic_load_relaxed (&(mutex->__data.__kind)) + & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0 || mutex->__data.__owner != PTHREAD_MUTEX_INCONSISTENT) return EINVAL; diff --git a/nptl/pthread_mutex_destroy.c b/nptl/pthread_mutex_destroy.c index 5a22611541..713ea68496 100644 --- a/nptl/pthread_mutex_destroy.c +++ b/nptl/pthread_mutex_destroy.c @@ -27,12 +27,17 @@ __pthread_mutex_destroy (pthread_mutex_t *mutex) { LIBC_PROBE (mutex_destroy, 1, mutex); - if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0 + /* See concurrency notes regarding __kind in struct __pthread_mutex_s + in sysdeps/nptl/bits/thread-shared-types.h. */ + if ((atomic_load_relaxed (&(mutex->__data.__kind)) + & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0 && mutex->__data.__nusers != 0) return EBUSY; - /* Set to an invalid value. */ - mutex->__data.__kind = -1; + /* Set to an invalid value. Relaxed MO is enough as it is undefined behavior + if the mutex is used after it has been destroyed. But you can reinitialize + it with pthread_mutex_init. */ + atomic_store_relaxed (&(mutex->__data.__kind), -1); return 0; } diff --git a/nptl/pthread_mutex_init.c b/nptl/pthread_mutex_init.c index d8fe473728..5cf290c272 100644 --- a/nptl/pthread_mutex_init.c +++ b/nptl/pthread_mutex_init.c @@ -101,7 +101,7 @@ __pthread_mutex_init (pthread_mutex_t *mutex, memset (mutex, '\0', __SIZEOF_PTHREAD_MUTEX_T); /* Copy the values from the attribute. */ - mutex->__data.__kind = imutexattr->mutexkind & ~PTHREAD_MUTEXATTR_FLAG_BITS; + int mutex_kind = imutexattr->mutexkind & ~PTHREAD_MUTEXATTR_FLAG_BITS; if ((imutexattr->mutexkind & PTHREAD_MUTEXATTR_FLAG_ROBUST) != 0) { @@ -111,17 +111,17 @@ __pthread_mutex_init (pthread_mutex_t *mutex, return ENOTSUP; #endif - mutex->__data.__kind |= PTHREAD_MUTEX_ROBUST_NORMAL_NP; + mutex_kind |= PTHREAD_MUTEX_ROBUST_NORMAL_NP; } switch (imutexattr->mutexkind & PTHREAD_MUTEXATTR_PROTOCOL_MASK) { case PTHREAD_PRIO_INHERIT << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT: - mutex->__data.__kind |= PTHREAD_MUTEX_PRIO_INHERIT_NP; + mutex_kind |= PTHREAD_MUTEX_PRIO_INHERIT_NP; break; case PTHREAD_PRIO_PROTECT << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT: - mutex->__data.__kind |= PTHREAD_MUTEX_PRIO_PROTECT_NP; + mutex_kind |= PTHREAD_MUTEX_PRIO_PROTECT_NP; int ceiling = (imutexattr->mutexkind & PTHREAD_MUTEXATTR_PRIO_CEILING_MASK) @@ -145,7 +145,11 @@ __pthread_mutex_init (pthread_mutex_t *mutex, FUTEX_PRIVATE_FLAG FUTEX_WAKE. */ if ((imutexattr->mutexkind & (PTHREAD_MUTEXATTR_FLAG_PSHARED | PTHREAD_MUTEXATTR_FLAG_ROBUST)) != 0) - mutex->__data.__kind |= PTHREAD_MUTEX_PSHARED_BIT; + mutex_kind |= PTHREAD_MUTEX_PSHARED_BIT; + + /* See concurrency notes regarding __kind in struct __pthread_mutex_s + in sysdeps/nptl/bits/thread-shared-types.h. */ + atomic_store_relaxed (&(mutex->__data.__kind), mutex_kind); /* Default values: mutex not used yet. */ // mutex->__count = 0; already done by memset diff --git a/nptl/pthread_mutex_lock.c b/nptl/pthread_mutex_lock.c index 1519c142bd..29cc143e6c 100644 --- a/nptl/pthread_mutex_lock.c +++ b/nptl/pthread_mutex_lock.c @@ -62,6 +62,8 @@ static int __pthread_mutex_lock_full (pthread_mutex_t *mutex) int __pthread_mutex_lock (pthread_mutex_t *mutex) { + /* See concurrency notes regarding mutex type which is loaded from __kind + in struct __pthread_mutex_s in sysdeps/nptl/bits/thread-shared-types.h. */ unsigned int type = PTHREAD_MUTEX_TYPE_ELISION (mutex); LIBC_PROBE (mutex_entry, 1, mutex); @@ -350,8 +352,14 @@ __pthread_mutex_lock_full (pthread_mutex_t *mutex) case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP: case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP: { - int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP; - int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP; + int kind, robust; + { + /* See concurrency notes regarding __kind in struct __pthread_mutex_s + in sysdeps/nptl/bits/thread-shared-types.h. */ + int mutex_kind = atomic_load_relaxed (&(mutex->__data.__kind)); + kind = mutex_kind & PTHREAD_MUTEX_KIND_MASK_NP; + robust = mutex_kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP; + } if (robust) { @@ -502,7 +510,10 @@ __pthread_mutex_lock_full (pthread_mutex_t *mutex) case PTHREAD_MUTEX_PP_NORMAL_NP: case PTHREAD_MUTEX_PP_ADAPTIVE_NP: { - int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP; + /* See concurrency notes regarding __kind in struct __pthread_mutex_s + in sysdeps/nptl/bits/thread-shared-types.h. */ + int kind = atomic_load_relaxed (&(mutex->__data.__kind)) + & PTHREAD_MUTEX_KIND_MASK_NP; oldval = mutex->__data.__lock; @@ -607,15 +618,18 @@ hidden_def (__pthread_mutex_lock) void __pthread_mutex_cond_lock_adjust (pthread_mutex_t *mutex) { - assert ((mutex->__data.__kind & PTHREAD_MUTEX_PRIO_INHERIT_NP) != 0); - assert ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0); - assert ((mutex->__data.__kind & PTHREAD_MUTEX_PSHARED_BIT) == 0); + /* See concurrency notes regarding __kind in struct __pthread_mutex_s + in sysdeps/nptl/bits/thread-shared-types.h. */ + int mutex_kind = atomic_load_relaxed (&(mutex->__data.__kind)); + assert ((mutex_kind & PTHREAD_MUTEX_PRIO_INHERIT_NP) != 0); + assert ((mutex_kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0); + assert ((mutex_kind & PTHREAD_MUTEX_PSHARED_BIT) == 0); /* Record the ownership. */ pid_t id = THREAD_GETMEM (THREAD_SELF, tid); mutex->__data.__owner = id; - if (mutex->__data.__kind == PTHREAD_MUTEX_PI_RECURSIVE_NP) + if (mutex_kind == PTHREAD_MUTEX_PI_RECURSIVE_NP) ++mutex->__data.__count; } #endif diff --git a/nptl/pthread_mutex_setprioceiling.c b/nptl/pthread_mutex_setprioceiling.c index 8594874f85..8306cabcf4 100644 --- a/nptl/pthread_mutex_setprioceiling.c +++ b/nptl/pthread_mutex_setprioceiling.c @@ -27,9 +27,10 @@ int pthread_mutex_setprioceiling (pthread_mutex_t *mutex, int prioceiling, int *old_ceiling) { - /* The low bits of __kind aren't ever changed after pthread_mutex_init, - so we don't need a lock yet. */ - if ((mutex->__data.__kind & PTHREAD_MUTEX_PRIO_PROTECT_NP) == 0) + /* See concurrency notes regarding __kind in struct __pthread_mutex_s + in sysdeps/nptl/bits/thread-shared-types.h. */ + if ((atomic_load_relaxed (&(mutex->__data.__kind)) + & PTHREAD_MUTEX_PRIO_PROTECT_NP) == 0) return EINVAL; /* See __init_sched_fifo_prio. */ diff --git a/nptl/pthread_mutex_timedlock.c b/nptl/pthread_mutex_timedlock.c index 28237b0e58..888c12fe28 100644 --- a/nptl/pthread_mutex_timedlock.c +++ b/nptl/pthread_mutex_timedlock.c @@ -53,6 +53,8 @@ __pthread_mutex_timedlock (pthread_mutex_t *mutex, /* We must not check ABSTIME here. If the thread does not block abstime must not be checked for a valid value. */ + /* See concurrency notes regarding mutex type which is loaded from __kind + in struct __pthread_mutex_s in sysdeps/nptl/bits/thread-shared-types.h. */ switch (__builtin_expect (PTHREAD_MUTEX_TYPE_ELISION (mutex), PTHREAD_MUTEX_TIMED_NP)) { @@ -338,8 +340,14 @@ __pthread_mutex_timedlock (pthread_mutex_t *mutex, case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP: case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP: { - int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP; - int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP; + int kind, robust; + { + /* See concurrency notes regarding __kind in struct __pthread_mutex_s + in sysdeps/nptl/bits/thread-shared-types.h. */ + int mutex_kind = atomic_load_relaxed (&(mutex->__data.__kind)); + kind = mutex_kind & PTHREAD_MUTEX_KIND_MASK_NP; + robust = mutex_kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP; + } if (robust) { @@ -509,7 +517,10 @@ __pthread_mutex_timedlock (pthread_mutex_t *mutex, case PTHREAD_MUTEX_PP_NORMAL_NP: case PTHREAD_MUTEX_PP_ADAPTIVE_NP: { - int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP; + /* See concurrency notes regarding __kind in struct __pthread_mutex_s + in sysdeps/nptl/bits/thread-shared-types.h. */ + int kind = atomic_load_relaxed (&(mutex->__data.__kind)) + & PTHREAD_MUTEX_KIND_MASK_NP; oldval = mutex->__data.__lock; diff --git a/nptl/pthread_mutex_trylock.c b/nptl/pthread_mutex_trylock.c index 7de61f4f68..8e01113b0f 100644 --- a/nptl/pthread_mutex_trylock.c +++ b/nptl/pthread_mutex_trylock.c @@ -36,6 +36,8 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) int oldval; pid_t id = THREAD_GETMEM (THREAD_SELF, tid); + /* See concurrency notes regarding mutex type which is loaded from __kind + in struct __pthread_mutex_s in sysdeps/nptl/bits/thread-shared-types.h. */ switch (__builtin_expect (PTHREAD_MUTEX_TYPE_ELISION (mutex), PTHREAD_MUTEX_TIMED_NP)) { @@ -92,6 +94,9 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) case PTHREAD_MUTEX_ROBUST_ADAPTIVE_NP: THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, &mutex->__data.__list.__next); + /* We need to set op_pending before starting the operation. Also + see comments at ENQUEUE_MUTEX. */ + __asm ("" ::: "memory"); oldval = mutex->__data.__lock; do @@ -117,7 +122,12 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) /* But it is inconsistent unless marked otherwise. */ mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT; + /* We must not enqueue the mutex before we have acquired it. + Also see comments at ENQUEUE_MUTEX. */ + __asm ("" ::: "memory"); ENQUEUE_MUTEX (mutex); + /* We need to clear op_pending after we enqueue the mutex. */ + __asm ("" ::: "memory"); THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); /* Note that we deliberately exist here. If we fall @@ -133,6 +143,8 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) int kind = PTHREAD_MUTEX_TYPE (mutex); if (kind == PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP) { + /* We do not need to ensure ordering wrt another memory + access. Also see comments at ENQUEUE_MUTEX. */ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); return EDEADLK; @@ -140,6 +152,8 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) if (kind == PTHREAD_MUTEX_ROBUST_RECURSIVE_NP) { + /* We do not need to ensure ordering wrt another memory + access. */ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); @@ -158,6 +172,9 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) id, 0); if (oldval != 0 && (oldval & FUTEX_OWNER_DIED) == 0) { + /* We haven't acquired the lock as it is already acquired by + another owner. We do not need to ensure ordering wrt another + memory access. */ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); return EBUSY; @@ -171,13 +188,20 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) if (oldval == id) lll_unlock (mutex->__data.__lock, PTHREAD_ROBUST_MUTEX_PSHARED (mutex)); + /* FIXME This violates the mutex destruction requirements. See + __pthread_mutex_unlock_full. */ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); return ENOTRECOVERABLE; } } while ((oldval & FUTEX_OWNER_DIED) != 0); + /* We must not enqueue the mutex before we have acquired it. + Also see comments at ENQUEUE_MUTEX. */ + __asm ("" ::: "memory"); ENQUEUE_MUTEX (mutex); + /* We need to clear op_pending after we enqueue the mutex. */ + __asm ("" ::: "memory"); THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); mutex->__data.__owner = id; @@ -199,14 +223,25 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP: case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP: { - int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP; - int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP; + int kind, robust; + { + /* See concurrency notes regarding __kind in struct __pthread_mutex_s + in sysdeps/nptl/bits/thread-shared-types.h. */ + int mutex_kind = atomic_load_relaxed (&(mutex->__data.__kind)); + kind = mutex_kind & PTHREAD_MUTEX_KIND_MASK_NP; + robust = mutex_kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP; + } if (robust) - /* Note: robust PI futexes are signaled by setting bit 0. */ - THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, - (void *) (((uintptr_t) &mutex->__data.__list.__next) - | 1)); + { + /* Note: robust PI futexes are signaled by setting bit 0. */ + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, + (void *) (((uintptr_t) &mutex->__data.__list.__next) + | 1)); + /* We need to set op_pending before starting the operation. Also + see comments at ENQUEUE_MUTEX. */ + __asm ("" ::: "memory"); + } oldval = mutex->__data.__lock; @@ -215,12 +250,16 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) { if (kind == PTHREAD_MUTEX_ERRORCHECK_NP) { + /* We do not need to ensure ordering wrt another memory + access. */ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); return EDEADLK; } if (kind == PTHREAD_MUTEX_RECURSIVE_NP) { + /* We do not need to ensure ordering wrt another memory + access. */ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); /* Just bump the counter. */ @@ -242,6 +281,9 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) { if ((oldval & FUTEX_OWNER_DIED) == 0) { + /* We haven't acquired the lock as it is already acquired by + another owner. We do not need to ensure ordering wrt another + memory access. */ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); return EBUSY; @@ -262,6 +304,9 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) if (INTERNAL_SYSCALL_ERROR_P (e, __err) && INTERNAL_SYSCALL_ERRNO (e, __err) == EWOULDBLOCK) { + /* The kernel has not yet finished the mutex owner death. + We do not need to ensure ordering wrt another memory + access. */ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); return EBUSY; @@ -279,7 +324,12 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) /* But it is inconsistent unless marked otherwise. */ mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT; + /* We must not enqueue the mutex before we have acquired it. + Also see comments at ENQUEUE_MUTEX. */ + __asm ("" ::: "memory"); ENQUEUE_MUTEX (mutex); + /* We need to clear op_pending after we enqueue the mutex. */ + __asm ("" ::: "memory"); THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); /* Note that we deliberately exit here. If we fall @@ -302,13 +352,20 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) PTHREAD_ROBUST_MUTEX_PSHARED (mutex)), 0, 0); + /* To the kernel, this will be visible after the kernel has + acquired the mutex in the syscall. */ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); return ENOTRECOVERABLE; } if (robust) { + /* We must not enqueue the mutex before we have acquired it. + Also see comments at ENQUEUE_MUTEX. */ + __asm ("" ::: "memory"); ENQUEUE_MUTEX_PI (mutex); + /* We need to clear op_pending after we enqueue the mutex. */ + __asm ("" ::: "memory"); THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); } @@ -325,7 +382,10 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) case PTHREAD_MUTEX_PP_NORMAL_NP: case PTHREAD_MUTEX_PP_ADAPTIVE_NP: { - int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP; + /* See concurrency notes regarding __kind in struct __pthread_mutex_s + in sysdeps/nptl/bits/thread-shared-types.h. */ + int kind = atomic_load_relaxed (&(mutex->__data.__kind)) + & PTHREAD_MUTEX_KIND_MASK_NP; oldval = mutex->__data.__lock; diff --git a/nptl/pthread_mutex_unlock.c b/nptl/pthread_mutex_unlock.c index 9ea62943b7..68d04d5395 100644 --- a/nptl/pthread_mutex_unlock.c +++ b/nptl/pthread_mutex_unlock.c @@ -35,6 +35,8 @@ int attribute_hidden __pthread_mutex_unlock_usercnt (pthread_mutex_t *mutex, int decr) { + /* See concurrency notes regarding mutex type which is loaded from __kind + in struct __pthread_mutex_s in sysdeps/nptl/bits/thread-shared-types.h. */ int type = PTHREAD_MUTEX_TYPE_ELISION (mutex); if (__builtin_expect (type & ~(PTHREAD_MUTEX_KIND_MASK_NP|PTHREAD_MUTEX_ELISION_FLAGS_NP), 0)) @@ -222,13 +224,19 @@ __pthread_mutex_unlock_full (pthread_mutex_t *mutex, int decr) /* If the previous owner died and the caller did not succeed in making the state consistent, mark the mutex as unrecoverable and make all waiters. */ - if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0 + /* See concurrency notes regarding __kind in struct __pthread_mutex_s + in sysdeps/nptl/bits/thread-shared-types.h. */ + if ((atomic_load_relaxed (&(mutex->__data.__kind)) + & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0 && __builtin_expect (mutex->__data.__owner == PTHREAD_MUTEX_INCONSISTENT, 0)) pi_notrecoverable: newowner = PTHREAD_MUTEX_NOTRECOVERABLE; - if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0) + /* See concurrency notes regarding __kind in struct __pthread_mutex_s + in sysdeps/nptl/bits/thread-shared-types.h. */ + if ((atomic_load_relaxed (&(mutex->__data.__kind)) + & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0) { continue_pi_robust: /* Remove mutex from the list. @@ -251,7 +259,10 @@ __pthread_mutex_unlock_full (pthread_mutex_t *mutex, int decr) /* Unlock. Load all necessary mutex data before releasing the mutex to not violate the mutex destruction requirements (see lll_unlock). */ - int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP; + /* See concurrency notes regarding __kind in struct __pthread_mutex_s + in sysdeps/nptl/bits/thread-shared-types.h. */ + int robust = atomic_load_relaxed (&(mutex->__data.__kind)) + & PTHREAD_MUTEX_ROBUST_NORMAL_NP; private = (robust ? PTHREAD_ROBUST_MUTEX_PSHARED (mutex) : PTHREAD_MUTEX_PSHARED (mutex)); diff --git a/nptl/pthread_rwlock_common.c b/nptl/pthread_rwlock_common.c index a290d08332..9ce36d1026 100644 --- a/nptl/pthread_rwlock_common.c +++ b/nptl/pthread_rwlock_common.c @@ -314,8 +314,8 @@ __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock, harmless because the flag is just about the state of __readers, and all threads set the flag under the same conditions. */ - while ((atomic_load_relaxed (&rwlock->__data.__readers) - & PTHREAD_RWLOCK_RWAITING) != 0) + while (((r = atomic_load_relaxed (&rwlock->__data.__readers)) + & PTHREAD_RWLOCK_RWAITING) != 0) { int private = __pthread_rwlock_get_private (rwlock); int err = futex_abstimed_wait (&rwlock->__data.__readers, diff --git a/nptl/pthread_rwlock_tryrdlock.c b/nptl/pthread_rwlock_tryrdlock.c index 4aec1fc15a..31a88d33a6 100644 --- a/nptl/pthread_rwlock_tryrdlock.c +++ b/nptl/pthread_rwlock_tryrdlock.c @@ -94,15 +94,22 @@ __pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock) /* Same as in __pthread_rwlock_rdlock_full: We started the read phase, so we are also responsible for updating the write-phase futex. Relaxed MO is sufficient. - Note that there can be no other reader that we have to wake - because all other readers will see the read phase started by us - (or they will try to start it themselves); if a writer started - the read phase, we cannot have started it. Furthermore, we - cannot discard a PTHREAD_RWLOCK_FUTEX_USED flag because we will - overwrite the value set by the most recent writer (or the readers - before it in case of explicit hand-over) and we know that there - are no waiting readers. */ - atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 0); + We have to do the same steps as a writer would when handing over the + read phase to use because other readers cannot distinguish between + us and the writer. + Note that __pthread_rwlock_tryrdlock callers will not have to be + woken up because they will either see the read phase started by us + or they will try to start it themselves; however, callers of + __pthread_rwlock_rdlock_full just increase the reader count and then + check what state the lock is in, so they cannot distinguish between + us and a writer that acquired and released the lock in the + meantime. */ + if ((atomic_exchange_relaxed (&rwlock->__data.__wrphase_futex, 0) + & PTHREAD_RWLOCK_FUTEX_USED) != 0) + { + int private = __pthread_rwlock_get_private (rwlock); + futex_wake (&rwlock->__data.__wrphase_futex, INT_MAX, private); + } } return 0; diff --git a/nptl/pthread_rwlock_trywrlock.c b/nptl/pthread_rwlock_trywrlock.c index 5a73eba756..f2e3443466 100644 --- a/nptl/pthread_rwlock_trywrlock.c +++ b/nptl/pthread_rwlock_trywrlock.c @@ -46,8 +46,15 @@ __pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock) &rwlock->__data.__readers, &r, r | PTHREAD_RWLOCK_WRPHASE | PTHREAD_RWLOCK_WRLOCKED)) { + /* We have become the primary writer and we cannot have shared + the PTHREAD_RWLOCK_FUTEX_USED flag with someone else, so we + can simply enable blocking (see full wrlock code). */ atomic_store_relaxed (&rwlock->__data.__writers_futex, 1); - atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 1); + /* If we started a write phase, we need to enable readers to + wait. If we did not, we must not change it because other threads + may have set the PTHREAD_RWLOCK_FUTEX_USED in the meantime. */ + if ((r & PTHREAD_RWLOCK_WRPHASE) == 0) + atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 1); atomic_store_relaxed (&rwlock->__data.__cur_writer, THREAD_GETMEM (THREAD_SELF, tid)); return 0; diff --git a/nptl/register-atfork.c b/nptl/register-atfork.c index 5ff1c1be8c..9edb7d4bbb 100644 --- a/nptl/register-atfork.c +++ b/nptl/register-atfork.c @@ -107,13 +107,14 @@ __unregister_atfork (void *dso_handle) } void -__run_fork_handlers (enum __run_fork_handler_type who) +__run_fork_handlers (enum __run_fork_handler_type who, _Bool do_locking) { struct fork_handler *runp; if (who == atfork_run_prepare) { - lll_lock (atfork_lock, LLL_PRIVATE); + if (do_locking) + lll_lock (atfork_lock, LLL_PRIVATE); size_t sl = fork_handler_list_size (&fork_handlers); for (size_t i = sl; i > 0; i--) { @@ -133,7 +134,8 @@ __run_fork_handlers (enum __run_fork_handler_type who) else if (who == atfork_run_parent && runp->parent_handler) runp->parent_handler (); } - lll_unlock (atfork_lock, LLL_PRIVATE); + if (do_locking) + lll_unlock (atfork_lock, LLL_PRIVATE); } } diff --git a/nptl/tst-audit-threads-mod1.c b/nptl/tst-audit-threads-mod1.c new file mode 100644 index 0000000000..615d5ee512 --- /dev/null +++ b/nptl/tst-audit-threads-mod1.c @@ -0,0 +1,74 @@ +/* Dummy audit library for test-audit-threads. + + 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 + +/* We must use a dummy LD_AUDIT module to force the dynamic loader to + *not* update the real PLT, and instead use a cached value for the + lazy resolution result. It is the update of that cached value that + we are testing for correctness by doing this. */ + +/* Library to be audited. */ +#define LIB "tst-audit-threads-mod2.so" +/* CALLNUM is the number of retNum functions. */ +#define CALLNUM 7999 + +#define CONCATX(a, b) __CONCAT (a, b) + +static int previous = 0; + +unsigned int +la_version (unsigned int ver) +{ + return 1; +} + +unsigned int +la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t *cookie) +{ + return LA_FLG_BINDTO | LA_FLG_BINDFROM; +} + +uintptr_t +CONCATX(la_symbind, __ELF_NATIVE_CLASS) (ElfW(Sym) *sym, + unsigned int ndx, + uintptr_t *refcook, + uintptr_t *defcook, + unsigned int *flags, + const char *symname) +{ + const char * retnum = "retNum"; + char * num = strstr (symname, retnum); + int n; + /* Validate if the symbols are getting called in the correct order. + This code is here to verify binutils does not optimize out the PLT + entries that require the symbol binding. */ + if (num != NULL) + { + n = atoi (num); + assert (n >= previous); + assert (n <= CALLNUM); + previous = n; + } + return sym->st_value; +} diff --git a/nptl/tst-audit-threads-mod2.c b/nptl/tst-audit-threads-mod2.c new file mode 100644 index 0000000000..f9817dd3dc --- /dev/null +++ b/nptl/tst-audit-threads-mod2.c @@ -0,0 +1,22 @@ +/* Shared object with a huge number of functions for test-audit-threads. + + 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 + . */ + +/* Define all the retNumN functions in a library. */ +#define definenum +#include "tst-audit-threads.h" diff --git a/nptl/tst-audit-threads.c b/nptl/tst-audit-threads.c new file mode 100644 index 0000000000..e4bf433bd8 --- /dev/null +++ b/nptl/tst-audit-threads.c @@ -0,0 +1,97 @@ +/* Test multi-threading using LD_AUDIT. + + 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 + . */ + +/* This test uses a dummy LD_AUDIT library (test-audit-threads-mod1) and a + library with a huge number of functions in order to validate lazy symbol + binding with an audit library. We use one thread per CPU to test that + concurrent lazy resolution does not have any defects which would cause + the process to fail. We use an LD_AUDIT library to force the testing of + the relocation resolution caching code in the dynamic loader i.e. + _dl_runtime_profile and _dl_profile_fixup. */ + +#include +#include +#include +#include + +static int do_test (void); + +/* This test usually takes less than 3s to run. However, there are cases that + take up to 30s. */ +#define TIMEOUT 60 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" + +/* Declare the functions we are going to call. */ +#define externnum +#include "tst-audit-threads.h" +#undef externnum + +int num_threads; +pthread_barrier_t barrier; + +void +sync_all (int num) +{ + pthread_barrier_wait (&barrier); +} + +void +call_all_ret_nums (void) +{ + /* Call each function one at a time from all threads. */ +#define callnum +#include "tst-audit-threads.h" +#undef callnum +} + +void * +thread_main (void *unused) +{ + call_all_ret_nums (); + return NULL; +} + +#define STR2(X) #X +#define STR(X) STR2(X) + +static int +do_test (void) +{ + int i; + pthread_t *threads; + + num_threads = get_nprocs (); + if (num_threads <= 1) + num_threads = 2; + + /* Used to synchronize all the threads after calling each retNumN. */ + xpthread_barrier_init (&barrier, NULL, num_threads); + + threads = (pthread_t *) xcalloc (num_threads, sizeof(pthread_t)); + for (i = 0; i < num_threads; i++) + threads[i] = xpthread_create(NULL, thread_main, NULL); + + for (i = 0; i < num_threads; i++) + xpthread_join(threads[i]); + + free (threads); + + return 0; +} diff --git a/nptl/tst-audit-threads.h b/nptl/tst-audit-threads.h new file mode 100644 index 0000000000..1c9ecc08df --- /dev/null +++ b/nptl/tst-audit-threads.h @@ -0,0 +1,92 @@ +/* Helper header for test-audit-threads. + + 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 + . */ + +/* We use this helper to create a large number of functions, all of + which will be resolved lazily and thus have their PLT updated. + This is done to provide enough functions that we can statistically + observe a thread vs. PLT resolution failure if one exists. */ + +#define CONCAT(a, b) a ## b +#define NUM(x, y) CONCAT (x, y) + +#define FUNC10(x) \ + FUNC (NUM (x, 0)); \ + FUNC (NUM (x, 1)); \ + FUNC (NUM (x, 2)); \ + FUNC (NUM (x, 3)); \ + FUNC (NUM (x, 4)); \ + FUNC (NUM (x, 5)); \ + FUNC (NUM (x, 6)); \ + FUNC (NUM (x, 7)); \ + FUNC (NUM (x, 8)); \ + FUNC (NUM (x, 9)) + +#define FUNC100(x) \ + FUNC10 (NUM (x, 0)); \ + FUNC10 (NUM (x, 1)); \ + FUNC10 (NUM (x, 2)); \ + FUNC10 (NUM (x, 3)); \ + FUNC10 (NUM (x, 4)); \ + FUNC10 (NUM (x, 5)); \ + FUNC10 (NUM (x, 6)); \ + FUNC10 (NUM (x, 7)); \ + FUNC10 (NUM (x, 8)); \ + FUNC10 (NUM (x, 9)) + +#define FUNC1000(x) \ + FUNC100 (NUM (x, 0)); \ + FUNC100 (NUM (x, 1)); \ + FUNC100 (NUM (x, 2)); \ + FUNC100 (NUM (x, 3)); \ + FUNC100 (NUM (x, 4)); \ + FUNC100 (NUM (x, 5)); \ + FUNC100 (NUM (x, 6)); \ + FUNC100 (NUM (x, 7)); \ + FUNC100 (NUM (x, 8)); \ + FUNC100 (NUM (x, 9)) + +#define FUNC7000() \ + FUNC1000 (1); \ + FUNC1000 (2); \ + FUNC1000 (3); \ + FUNC1000 (4); \ + FUNC1000 (5); \ + FUNC1000 (6); \ + FUNC1000 (7); + +#ifdef FUNC +# undef FUNC +#endif + +#ifdef externnum +# define FUNC(x) extern int CONCAT (retNum, x) (void) +#endif + +#ifdef definenum +# define FUNC(x) int CONCAT (retNum, x) (void) { return x; } +#endif + +#ifdef callnum +# define FUNC(x) CONCAT (retNum, x) (); sync_all (x) +#endif + +/* A value of 7000 functions is chosen as an arbitrarily large + number of functions that will allow us enough attempts to + verify lazy resolution operation. */ +FUNC7000 (); diff --git a/nptl/tst-mutex10.c b/nptl/tst-mutex10.c new file mode 100644 index 0000000000..e1113ca60a --- /dev/null +++ b/nptl/tst-mutex10.c @@ -0,0 +1,109 @@ +/* Testing race while enabling lock elision. + 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 + +static pthread_barrier_t barrier; +static pthread_mutex_t mutex; +static long long int iteration_count = 1000000; +static unsigned int thread_count = 3; + +static void * +thr_func (void *arg) +{ + long long int i; + for (i = 0; i < iteration_count; i++) + { + if ((uintptr_t) arg == 0) + { + xpthread_mutex_destroy (&mutex); + xpthread_mutex_init (&mutex, NULL); + } + + xpthread_barrier_wait (&barrier); + + /* Test if enabling lock elision works if it is enabled concurrently. + There was a race in FORCE_ELISION macro which leads to either + pthread_mutex_destroy returning EBUSY as the owner was recorded + by pthread_mutex_lock - in "normal mutex" code path - but was not + resetted in pthread_mutex_unlock - in "elision" code path. + Or it leads to the assertion in nptl/pthread_mutex_lock.c: + assert (mutex->__data.__owner == 0); + Please ensure that the test is run with lock elision: + export GLIBC_TUNABLES=glibc.elision.enable=1 */ + xpthread_mutex_lock (&mutex); + xpthread_mutex_unlock (&mutex); + + xpthread_barrier_wait (&barrier); + } + return NULL; +} + +static int +do_test (void) +{ + unsigned int i; + printf ("Starting %d threads to run %lld iterations.\n", + thread_count, iteration_count); + + pthread_t *threads = xmalloc (thread_count * sizeof (pthread_t)); + xpthread_barrier_init (&barrier, NULL, thread_count); + xpthread_mutex_init (&mutex, NULL); + + for (i = 0; i < thread_count; i++) + threads[i] = xpthread_create (NULL, thr_func, (void *) (uintptr_t) i); + + for (i = 0; i < thread_count; i++) + xpthread_join (threads[i]); + + xpthread_barrier_destroy (&barrier); + free (threads); + + return EXIT_SUCCESS; +} + +#define OPT_ITERATIONS 10000 +#define OPT_THREADS 10001 +#define CMDLINE_OPTIONS \ + { "iterations", required_argument, NULL, OPT_ITERATIONS }, \ + { "threads", required_argument, NULL, OPT_THREADS }, +static void +cmdline_process (int c) +{ + long long int arg = strtoll (optarg, NULL, 0); + switch (c) + { + case OPT_ITERATIONS: + if (arg > 0) + iteration_count = arg; + break; + case OPT_THREADS: + if (arg > 0 && arg < 100) + thread_count = arg; + break; + } +} +#define CMDLINE_PROCESS cmdline_process +#define TIMEOUT 50 +#include diff --git a/nptl/tst-rwlock-pwn.c b/nptl/tst-rwlock-pwn.c new file mode 100644 index 0000000000..c39dd70973 --- /dev/null +++ b/nptl/tst-rwlock-pwn.c @@ -0,0 +1,87 @@ +/* Test rwlock with PREFER_WRITER_NONRECURSIVE_NP (bug 23861). + 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 + +/* We choose 10 iterations because this happens to be able to trigger the + stall on contemporary hardware. */ +#define LOOPS 10 +/* We need 3 threads to trigger bug 23861. One thread as a writer, and + two reader threads. The test verifies that the second-to-last reader + is able to notify the *last* reader that it should be done waiting. + If the second-to-last reader fails to notify the last reader or does + so incorrectly then the last reader may stall indefinitely. */ +#define NTHREADS 3 + +_Atomic int do_exit; +pthread_rwlockattr_t mylock_attr; +pthread_rwlock_t mylock; + +void * +run_loop (void *a) +{ + while (!do_exit) + { + if (random () & 1) + { + xpthread_rwlock_wrlock (&mylock); + xpthread_rwlock_unlock (&mylock); + } + else + { + xpthread_rwlock_rdlock (&mylock); + xpthread_rwlock_unlock (&mylock); + } + } + return NULL; +} + +int +do_test (void) +{ + xpthread_rwlockattr_init (&mylock_attr); + xpthread_rwlockattr_setkind_np (&mylock_attr, + PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP); + xpthread_rwlock_init (&mylock, &mylock_attr); + + for (int n = 0; n < LOOPS; n++) + { + pthread_t tids[NTHREADS]; + do_exit = 0; + for (int i = 0; i < NTHREADS; i++) + tids[i] = xpthread_create (NULL, run_loop, NULL); + /* Let the threads run for some time. */ + sleep (1); + printf ("Exiting..."); + fflush (stdout); + do_exit = 1; + for (int i = 0; i < NTHREADS; i++) + xpthread_join (tids[i]); + printf ("done.\n"); + } + pthread_rwlock_destroy (&mylock); + pthread_rwlockattr_destroy (&mylock_attr); + return 0; +} + +#define TIMEOUT (DEFAULT_TIMEOUT + 3 * LOOPS) +#include diff --git a/nptl/tst-rwlock-tryrdlock-stall.c b/nptl/tst-rwlock-tryrdlock-stall.c new file mode 100644 index 0000000000..5e476da2b8 --- /dev/null +++ b/nptl/tst-rwlock-tryrdlock-stall.c @@ -0,0 +1,355 @@ +/* Bug 23844: Test for pthread_rwlock_tryrdlock stalls. + Copyright (C) 2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +/* For a full analysis see comment: + https://sourceware.org/bugzilla/show_bug.cgi?id=23844#c14 + + Provided here for reference: + + --- Analysis of pthread_rwlock_tryrdlock() stall --- + A read lock begins to execute. + + In __pthread_rwlock_rdlock_full: + + We can attempt a read lock, but find that the lock is + in a write phase (PTHREAD_RWLOCK_WRPHASE, or WP-bit + is set), and the lock is held by a primary writer + (PTHREAD_RWLOCK_WRLOCKED is set). In this case we must + wait for explicit hand over from the writer to us or + one of the other waiters. The read lock threads are + about to execute: + + 341 r = (atomic_fetch_add_acquire (&rwlock->__data.__readers, + 342 (1 << PTHREAD_RWLOCK_READER_SHIFT)) + 343 + (1 << PTHREAD_RWLOCK_READER_SHIFT)); + + An unlock beings to execute. + + Then in __pthread_rwlock_wrunlock: + + 547 unsigned int r = atomic_load_relaxed (&rwlock->__data.__readers); + ... + 549 while (!atomic_compare_exchange_weak_release + 550 (&rwlock->__data.__readers, &r, + 551 ((r ^ PTHREAD_RWLOCK_WRLOCKED) + 552 ^ ((r >> PTHREAD_RWLOCK_READER_SHIFT) == 0 ? 0 + 553 : PTHREAD_RWLOCK_WRPHASE)))) + 554 { + ... + 556 } + + We clear PTHREAD_RWLOCK_WRLOCKED, and if there are + no readers so we leave the lock in PTHRAD_RWLOCK_WRPHASE. + + Back in the read lock. + + The read lock adjusts __readres as above. + + 383 while ((r & PTHREAD_RWLOCK_WRPHASE) != 0 + 384 && (r & PTHREAD_RWLOCK_WRLOCKED) == 0) + 385 { + ... + 390 if (atomic_compare_exchange_weak_acquire (&rwlock->__data.__readers, &r, + 391 r ^ PTHREAD_RWLOCK_WRPHASE)) + 392 { + + And then attemps to start the read phase. + + Assume there happens to be a tryrdlock at this point, noting + that PTHREAD_RWLOCK_WRLOCKED is clear, and PTHREAD_RWLOCK_WRPHASE + is 1. So the try lock attemps to start the read phase. + + In __pthread_rwlock_tryrdlock: + + 44 if ((r & PTHREAD_RWLOCK_WRPHASE) == 0) + 45 { + ... + 49 if (((r & PTHREAD_RWLOCK_WRLOCKED) != 0) + 50 && (rwlock->__data.__flags + 51 == PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP)) + 52 return EBUSY; + 53 rnew = r + (1 << PTHREAD_RWLOCK_READER_SHIFT); + 54 } + ... + 89 while (!atomic_compare_exchange_weak_acquire (&rwlock->__data.__readers, + 90 &r, rnew)); + + And succeeds. + + Back in the write unlock: + + 557 if ((r >> PTHREAD_RWLOCK_READER_SHIFT) != 0) + 558 { + ... + 563 if ((atomic_exchange_relaxed (&rwlock->__data.__wrphase_futex, 0) + 564 & PTHREAD_RWLOCK_FUTEX_USED) != 0) + 565 futex_wake (&rwlock->__data.__wrphase_futex, INT_MAX, private); + 566 } + + We note that PTHREAD_RWLOCK_FUTEX_USED is non-zero + and don't wake anyone. This is OK because we handed + over to the trylock. It will be the trylock's responsibility + to wake any waiters. + + Back in the read lock: + + The read lock fails to install PTHRAD_REWLOCK_WRPHASE as 0 because + the __readers value was adjusted by the trylock, and so it falls through + to waiting on the lock for explicit handover from either a new writer + or a new reader. + + 448 int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex, + 449 1 | PTHREAD_RWLOCK_FUTEX_USED, + 450 abstime, private); + + We use PTHREAD_RWLOCK_FUTEX_USED to indicate the futex + is in use. + + At this point we have readers waiting on the read lock + to unlock. The wrlock is done. The trylock is finishing + the installation of the read phase. + + 92 if ((r & PTHREAD_RWLOCK_WRPHASE) != 0) + 93 { + ... + 105 atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 0); + 106 } + + The trylock does note that we were the one that + installed the read phase, but the comments are not + correct, the execution ordering above shows that + readers might indeed be waiting, and they are. + + The atomic_store_relaxed throws away PTHREAD_RWLOCK_FUTEX_USED, + and the waiting reader is never worken becuase as noted + above it is conditional on the futex being used. + + The solution is for the trylock thread to inspect + PTHREAD_RWLOCK_FUTEX_USED and wake the waiting readers. + + --- Analysis of pthread_rwlock_trywrlock() stall --- + + A write lock begins to execute, takes the write lock, + and then releases the lock... + + In pthread_rwlock_wrunlock(): + + 547 unsigned int r = atomic_load_relaxed (&rwlock->__data.__readers); + ... + 549 while (!atomic_compare_exchange_weak_release + 550 (&rwlock->__data.__readers, &r, + 551 ((r ^ PTHREAD_RWLOCK_WRLOCKED) + 552 ^ ((r >> PTHREAD_RWLOCK_READER_SHIFT) == 0 ? 0 + 553 : PTHREAD_RWLOCK_WRPHASE)))) + 554 { + ... + 556 } + + ... leaving it in the write phase with zero readers + (the case where we leave the write phase in place + during a write unlock). + + A write trylock begins to execute. + + In __pthread_rwlock_trywrlock: + + 40 while (((r & PTHREAD_RWLOCK_WRLOCKED) == 0) + 41 && (((r >> PTHREAD_RWLOCK_READER_SHIFT) == 0) + 42 || (prefer_writer && ((r & PTHREAD_RWLOCK_WRPHASE) != 0)))) + 43 { + + The lock is not locked. + + There are no readers. + + 45 if (atomic_compare_exchange_weak_acquire ( + 46 &rwlock->__data.__readers, &r, + 47 r | PTHREAD_RWLOCK_WRPHASE | PTHREAD_RWLOCK_WRLOCKED)) + + We atomically install the write phase and we take the + exclusive write lock. + + 48 { + 49 atomic_store_relaxed (&rwlock->__data.__writers_futex, 1); + + We get this far. + + A reader lock begins to execute. + + In pthread_rwlock_rdlock: + + 437 for (;;) + 438 { + 439 while (((wpf = atomic_load_relaxed (&rwlock->__data.__wrphase_futex)) + 440 | PTHREAD_RWLOCK_FUTEX_USED) == (1 | PTHREAD_RWLOCK_FUTEX_USED)) + 441 { + 442 int private = __pthread_rwlock_get_private (rwlock); + 443 if (((wpf & PTHREAD_RWLOCK_FUTEX_USED) == 0) + 444 && (!atomic_compare_exchange_weak_relaxed + 445 (&rwlock->__data.__wrphase_futex, + 446 &wpf, wpf | PTHREAD_RWLOCK_FUTEX_USED))) + 447 continue; + 448 int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex, + 449 1 | PTHREAD_RWLOCK_FUTEX_USED, + 450 abstime, private); + + We are in a write phase, so the while() on line 439 is true. + + The value of wpf does not have PTHREAD_RWLOCK_FUTEX_USED set + since this is the first reader to lock. + + The atomic operation sets wpf with PTHREAD_RELOCK_FUTEX_USED + on the expectation that this reader will be woken during + the handoff. + + Back in pthread_rwlock_trywrlock: + + 50 atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 1); + 51 atomic_store_relaxed (&rwlock->__data.__cur_writer, + 52 THREAD_GETMEM (THREAD_SELF, tid)); + 53 return 0; + 54 } + ... + 57 } + + We write 1 to __wrphase_futex discarding PTHREAD_RWLOCK_FUTEX_USED, + and so in the unlock we will not awaken the waiting reader. + + The solution to this is to realize that if we did not start the write + phase we need not write 1 or any other value to __wrphase_futex. + This ensures that any readers (which saw __wrphase_futex != 0) can + set PTHREAD_RWLOCK_FUTEX_USED and this can be used at unlock to + wake them. + + If we installed the write phase then all other readers are looping + here: + + In __pthread_rwlock_rdlock_full: + + 437 for (;;) + 438 { + 439 while (((wpf = atomic_load_relaxed (&rwlock->__data.__wrphase_futex)) + 440 | PTHREAD_RWLOCK_FUTEX_USED) == (1 | PTHREAD_RWLOCK_FUTEX_USED)) + 441 { + ... + 508 } + + waiting for the write phase to be installed or removed before they + can begin waiting on __wrphase_futex (part of the algorithm), or + taking a concurrent read lock, and thus we can safely write 1 to + __wrphase_futex. + + If we did not install the write phase then the readers may already + be waiting on the futex, the original writer wrote 1 to __wrphase_futex + as part of starting the write phase, and we cannot also write 1 + without loosing the PTHREAD_RWLOCK_FUTEX_USED bit. + + --- + + Summary for the pthread_rwlock_tryrdlock() stall: + + The stall is caused by pthread_rwlock_tryrdlock failing to check + that PTHREAD_RWLOCK_FUTEX_USED is set in the __wrphase_futex futex + and then waking the futex. + + The fix for bug 23844 ensures that waiters on __wrphase_futex are + correctly woken. Before the fix the test stalls as readers can + wait forever on __wrphase_futex. */ + +#include +#include +#include +#include +#include +#include + +/* We need only one lock to reproduce the issue. We will need multiple + threads to get the exact case where we have a read, try, and unlock + all interleaving to produce the case where the readers are waiting + and the try fails to wake them. */ +pthread_rwlock_t onelock; + +/* The number of threads is arbitrary but empirically chosen to have + enough threads that we see the condition where waiting readers are + not woken by a successful tryrdlock. */ +#define NTHREADS 32 + +_Atomic int do_exit; + +void * +run_loop (void *arg) +{ + int i = 0, ret; + while (!do_exit) + { + /* Arbitrarily choose if we are the writer or reader. Choose a + high enough ratio of readers to writers to make it likely + that readers block (and eventually are susceptable to + stalling). + + If we are a writer, take the write lock, and then unlock. + If we are a reader, try the lock, then lock, then unlock. */ + if ((i % 8) != 0) + xpthread_rwlock_wrlock (&onelock); + else + { + if ((ret = pthread_rwlock_tryrdlock (&onelock)) != 0) + { + if (ret == EBUSY) + xpthread_rwlock_rdlock (&onelock); + else + exit (EXIT_FAILURE); + } + } + /* Thread does some work and then unlocks. */ + xpthread_rwlock_unlock (&onelock); + i++; + } + return NULL; +} + +int +do_test (void) +{ + int i; + pthread_t tids[NTHREADS]; + xpthread_rwlock_init (&onelock, NULL); + for (i = 0; i < NTHREADS; i++) + tids[i] = xpthread_create (NULL, run_loop, NULL); + /* Run for some amount of time. Empirically speaking exercising + the stall via pthread_rwlock_tryrdlock is much harder, and on + a 3.5GHz 4 core x86_64 VM system it takes somewhere around + 20-200s to stall, approaching 100% stall past 200s. We can't + wait that long for a regression test so we just test for 20s, + and expect the stall to happen with a 5-10% chance (enough for + developers to see). */ + sleep (20); + /* Then exit. */ + printf ("INFO: Exiting...\n"); + do_exit = 1; + /* If any readers stalled then we will timeout waiting for them. */ + for (i = 0; i < NTHREADS; i++) + xpthread_join (tids[i]); + printf ("INFO: Done.\n"); + xpthread_rwlock_destroy (&onelock); + printf ("PASS: No pthread_rwlock_tryrdlock stalls detected.\n"); + return 0; +} + +#define TIMEOUT 30 +#include diff --git a/nptl/tst-rwlock-trywrlock-stall.c b/nptl/tst-rwlock-trywrlock-stall.c new file mode 100644 index 0000000000..14d27cbcbc --- /dev/null +++ b/nptl/tst-rwlock-trywrlock-stall.c @@ -0,0 +1,108 @@ +/* Bug 23844: Test for pthread_rwlock_trywrlock stalls. + Copyright (C) 2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +/* For a full analysis see comments in tst-rwlock-tryrdlock-stall.c. + + Summary for the pthread_rwlock_trywrlock() stall: + + The stall is caused by pthread_rwlock_trywrlock setting + __wrphase_futex futex to 1 and loosing the + PTHREAD_RWLOCK_FUTEX_USED bit. + + The fix for bug 23844 ensures that waiters on __wrphase_futex are + correctly woken. Before the fix the test stalls as readers can + wait forever on __wrphase_futex. */ + +#include +#include +#include +#include +#include +#include + +/* We need only one lock to reproduce the issue. We will need multiple + threads to get the exact case where we have a read, try, and unlock + all interleaving to produce the case where the readers are waiting + and the try clears the PTHREAD_RWLOCK_FUTEX_USED bit and a + subsequent unlock fails to wake them. */ +pthread_rwlock_t onelock; + +/* The number of threads is arbitrary but empirically chosen to have + enough threads that we see the condition where waiting readers are + not woken by a successful unlock. */ +#define NTHREADS 32 + +_Atomic int do_exit; + +void * +run_loop (void *arg) +{ + int i = 0, ret; + while (!do_exit) + { + /* Arbitrarily choose if we are the writer or reader. Choose a + high enough ratio of readers to writers to make it likely + that readers block (and eventually are susceptable to + stalling). + + If we are a writer, take the write lock, and then unlock. + If we are a reader, try the lock, then lock, then unlock. */ + if ((i % 8) != 0) + { + if ((ret = pthread_rwlock_trywrlock (&onelock)) != 0) + { + if (ret == EBUSY) + xpthread_rwlock_wrlock (&onelock); + else + exit (EXIT_FAILURE); + } + } + else + xpthread_rwlock_rdlock (&onelock); + /* Thread does some work and then unlocks. */ + xpthread_rwlock_unlock (&onelock); + i++; + } + return NULL; +} + +int +do_test (void) +{ + int i; + pthread_t tids[NTHREADS]; + xpthread_rwlock_init (&onelock, NULL); + for (i = 0; i < NTHREADS; i++) + tids[i] = xpthread_create (NULL, run_loop, NULL); + /* Run for some amount of time. The pthread_rwlock_tryrwlock stall + is very easy to trigger and happens in seconds under the test + conditions. */ + sleep (10); + /* Then exit. */ + printf ("INFO: Exiting...\n"); + do_exit = 1; + /* If any readers stalled then we will timeout waiting for them. */ + for (i = 0; i < NTHREADS; i++) + xpthread_join (tids[i]); + printf ("INFO: Done.\n"); + xpthread_rwlock_destroy (&onelock); + printf ("PASS: No pthread_rwlock_tryrwlock stalls detected.\n"); + return 0; +} + +#include diff --git a/nptl/tst-unwind-thread.c b/nptl/tst-unwind-thread.c new file mode 100644 index 0000000000..d5c38e3709 --- /dev/null +++ b/nptl/tst-unwind-thread.c @@ -0,0 +1,2 @@ +#define USE_PTHREADS 1 +#include "../elf/tst-unwind-main.c" diff --git a/nscd/Makefile b/nscd/Makefile index b713a84c49..eb23c01a39 100644 --- a/nscd/Makefile +++ b/nscd/Makefile @@ -36,7 +36,7 @@ nscd-modules := nscd connections pwdcache getpwnam_r getpwuid_r grpcache \ getsrvbynm_r getsrvbypt_r servicescache \ dbg_log nscd_conf nscd_stat cache mem nscd_setup_thread \ xmalloc xstrdup aicache initgrcache gai res_hconf \ - netgroupcache + netgroupcache nscd-inet_addr ifeq ($(build-nscd)$(have-thread-library),yesyes) diff --git a/nscd/gai.c b/nscd/gai.c index 24bdfee1db..68a4abd30e 100644 --- a/nscd/gai.c +++ b/nscd/gai.c @@ -19,7 +19,6 @@ /* This file uses the getaddrinfo code but it compiles it without NSCD support. We just need a few symbol renames. */ -#define __inet_aton inet_aton #define __ioctl ioctl #define __getsockname getsockname #define __socket socket @@ -34,6 +33,12 @@ #define __getifaddrs getifaddrs #define __freeifaddrs freeifaddrs +/* We do not want to export __inet_aton_exact. Get the prototype and + change its visibility to hidden. */ +#include +__typeof__ (__inet_aton_exact) __inet_aton_exact + __attribute__ ((visibility ("hidden"))); + /* We are nscd, so we don't want to be talking to ourselves. */ #undef USE_NSCD diff --git a/nscd/gethstbynm3_r.c b/nscd/gethstbynm3_r.c index 7beb9dce9f..f792c4fcd0 100644 --- a/nscd/gethstbynm3_r.c +++ b/nscd/gethstbynm3_r.c @@ -38,8 +38,6 @@ #define HAVE_LOOKUP_BUFFER 1 #define HAVE_AF 1 -#define __inet_aton inet_aton - /* We are nscd, so we don't want to be talking to ourselves. */ #undef USE_NSCD diff --git a/nscd/initgrcache.c b/nscd/initgrcache.c index 2c74951f57..4764f14a45 100644 --- a/nscd/initgrcache.c +++ b/nscd/initgrcache.c @@ -159,7 +159,7 @@ addinitgroupsX (struct database_dyn *db, int fd, request_header *req, /* This is really only for debugging. */ if (NSS_STATUS_TRYAGAIN > status || status > NSS_STATUS_RETURN) - __libc_fatal ("illegal status in internal_getgrouplist"); + __libc_fatal ("Illegal status in internal_getgrouplist.\n"); any_success |= status == NSS_STATUS_SUCCESS; diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c index 2b35389cc8..87059fb280 100644 --- a/nscd/netgroupcache.c +++ b/nscd/netgroupcache.c @@ -113,7 +113,8 @@ do_notfound (struct database_dyn *db, int fd, request_header *req, static time_t addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, const char *key, uid_t uid, struct hashentry *he, - struct datahead *dh, struct dataset **resultp) + struct datahead *dh, struct dataset **resultp, + void **tofreep) { if (__glibc_unlikely (debug_level > 0)) { @@ -139,6 +140,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, size_t group_len = strlen (key) + 1; struct name_list *first_needed = alloca (sizeof (struct name_list) + group_len); + *tofreep = NULL; if (netgroup_database == NULL && __nss_database_lookup ("netgroup", NULL, NULL, &netgroup_database)) @@ -151,6 +153,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, memset (&data, '\0', sizeof (data)); buffer = xmalloc (buflen); + *tofreep = buffer; first_needed->next = first_needed; memcpy (first_needed->name, key, group_len); data.needed_groups = first_needed; @@ -439,8 +442,6 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, } out: - free (buffer); - *resultp = dataset; return timeout; @@ -477,8 +478,12 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req, group, group_len, db, uid); time_t timeout; + void *tofree; if (result != NULL) - timeout = result->head.timeout; + { + timeout = result->head.timeout; + tofree = NULL; + } else { request_header req_get = @@ -487,7 +492,7 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req, .key_len = group_len }; timeout = addgetnetgrentX (db, -1, &req_get, group, uid, NULL, NULL, - &result); + &result, &tofree); } struct indataset @@ -560,7 +565,7 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req, ++dh->nreloads; if (cacheable) pthread_rwlock_unlock (&db->lock); - return timeout; + goto out; } if (he == NULL) @@ -596,17 +601,30 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req, dh->usable = false; } + out: + free (tofree); return timeout; } +static time_t +addgetnetgrentX_ignore (struct database_dyn *db, int fd, request_header *req, + const char *key, uid_t uid, struct hashentry *he, + struct datahead *dh) +{ + struct dataset *ignore; + void *tofree; + time_t timeout = addgetnetgrentX (db, fd, req, key, uid, he, dh, + &ignore, &tofree); + free (tofree); + return timeout; +} + void addgetnetgrent (struct database_dyn *db, int fd, request_header *req, void *key, uid_t uid) { - struct dataset *ignore; - - addgetnetgrentX (db, fd, req, key, uid, NULL, NULL, &ignore); + addgetnetgrentX_ignore (db, fd, req, key, uid, NULL, NULL); } @@ -619,10 +637,8 @@ readdgetnetgrent (struct database_dyn *db, struct hashentry *he, .type = GETNETGRENT, .key_len = he->len }; - struct dataset *ignore; - - return addgetnetgrentX (db, -1, &req, db->data + he->key, he->owner, he, dh, - &ignore); + return addgetnetgrentX_ignore + (db, -1, &req, db->data + he->key, he->owner, he, dh); } diff --git a/nscd/nscd-inet_addr.c b/nscd/nscd-inet_addr.c new file mode 100644 index 0000000000..f366b9567d --- /dev/null +++ b/nscd/nscd-inet_addr.c @@ -0,0 +1,32 @@ +/* Legacy IPv4 text-to-address functions. Version for nscd. + Copyright (C) 2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for 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 + +/* We do not want to export __inet_aton_exact. Get the prototype and + change the visibility to hidden. */ +#include +__typeof__ (__inet_aton_exact) __inet_aton_exact + __attribute__ ((visibility ("hidden"))); + +/* Do not provide definitions of the public symbols exported from + libc. */ +#undef weak_alias +#define weak_alias(from, to) + +#include diff --git a/nscd/nscd_conf.c b/nscd/nscd_conf.c index 265a02434d..7293b795b6 100644 --- a/nscd/nscd_conf.c +++ b/nscd/nscd_conf.c @@ -190,7 +190,10 @@ nscd_parse_file (const char *fname, struct database_dyn dbs[lastdb]) if (!arg1) error (0, 0, _("Must specify user name for server-user option")); else - server_user = xstrdup (arg1); + { + free ((char *) server_user); + server_user = xstrdup (arg1); + } } else if (strcmp (entry, "stat-user") == 0) { @@ -198,6 +201,7 @@ nscd_parse_file (const char *fname, struct database_dyn dbs[lastdb]) error (0, 0, _("Must specify user name for stat-user option")); else { + free ((char *) stat_user); stat_user = xstrdup (arg1); struct passwd *pw = getpwnam (stat_user); diff --git a/nss/Makefile b/nss/Makefile index 66fac7f5b8..5209fc0456 100644 --- a/nss/Makefile +++ b/nss/Makefile @@ -65,6 +65,7 @@ ifeq (yes,$(build-shared)) tests += tst-nss-files-hosts-erange tests += tst-nss-files-hosts-multi tests += tst-nss-files-hosts-getent +tests += tst-nss-files-alias-leak endif # If we have a thread library then we can test cancellation against @@ -171,3 +172,5 @@ endif $(objpfx)tst-nss-files-hosts-erange: $(libdl) $(objpfx)tst-nss-files-hosts-multi: $(libdl) $(objpfx)tst-nss-files-hosts-getent: $(libdl) +$(objpfx)tst-nss-files-alias-leak: $(libdl) +$(objpfx)tst-nss-files-alias-leak.out: $(objpfx)/libnss_files.so diff --git a/nss/digits_dots.c b/nss/digits_dots.c index 39bff38865..5441bce16e 100644 --- a/nss/digits_dots.c +++ b/nss/digits_dots.c @@ -29,7 +29,6 @@ #include "nsswitch.h" #ifdef USE_NSCD -# define inet_aton __inet_aton # include #endif @@ -160,7 +159,7 @@ __nss_hostname_digits_dots_context (struct resolv_context *ctx, 255.255.255.255? The test below will succeed spuriously... ??? */ if (af == AF_INET) - ok = __inet_aton (name, (struct in_addr *) host_addr); + ok = __inet_aton_exact (name, (struct in_addr *) host_addr); else { assert (af == AF_INET6); diff --git a/nss/nss_files/files-alias.c b/nss/nss_files/files-alias.c index cfd34b66b9..35b0bfc5d2 100644 --- a/nss/nss_files/files-alias.c +++ b/nss/nss_files/files-alias.c @@ -221,6 +221,13 @@ get_next_alias (FILE *stream, const char *match, struct aliasent *result, { while (! feof_unlocked (listfile)) { + if (room_left < 2) + { + free (old_line); + fclose (listfile); + goto no_more_room; + } + first_unused[room_left - 1] = '\xff'; line = fgets_unlocked (first_unused, room_left, listfile); @@ -229,6 +236,7 @@ get_next_alias (FILE *stream, const char *match, struct aliasent *result, if (first_unused[room_left - 1] != '\xff') { free (old_line); + fclose (listfile); goto no_more_room; } @@ -256,6 +264,7 @@ get_next_alias (FILE *stream, const char *match, struct aliasent *result, + __alignof__ (char *))) { free (old_line); + fclose (listfile); goto no_more_room; } room_left -= ((first_unused - cp) diff --git a/nss/nsswitch.c b/nss/nsswitch.c index ee46f24424..3c48b4b85e 100644 --- a/nss/nsswitch.c +++ b/nss/nsswitch.c @@ -235,7 +235,7 @@ __nss_next2 (service_user **ni, const char *fct_name, const char *fct2_name, /* This is really only for debugging. */ if (__builtin_expect (NSS_STATUS_TRYAGAIN > status || status > NSS_STATUS_RETURN, 0)) - __libc_fatal ("illegal status in __nss_next"); + __libc_fatal ("Illegal status in __nss_next.\n"); if (nss_next_action (*ni, status) == NSS_ACTION_RETURN) return 1; diff --git a/nss/tst-nss-files-alias-leak.c b/nss/tst-nss-files-alias-leak.c new file mode 100644 index 0000000000..26d38e2dba --- /dev/null +++ b/nss/tst-nss-files-alias-leak.c @@ -0,0 +1,237 @@ +/* Check for file descriptor leak in alias :include: processing (bug 23521). + 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 +#include +#include +#include +#include +#include + +static struct support_chroot *chroot_env; + +/* Number of the aliases for the "many" user. This must be large + enough to trigger reallocation for the pointer array, but result in + answers below the maximum size tried in do_test. */ +enum { many_aliases = 30 }; + +static void +prepare (int argc, char **argv) +{ + chroot_env = support_chroot_create + ((struct support_chroot_configuration) { } ); + + char *path = xasprintf ("%s/etc/aliases", chroot_env->path_chroot); + add_temp_file (path); + support_write_file_string + (path, + "user1: :include:/etc/aliases.user1\n" + "user2: :include:/etc/aliases.user2\n" + "comment: comment1, :include:/etc/aliases.comment\n" + "many: :include:/etc/aliases.many\n"); + free (path); + + path = xasprintf ("%s/etc/aliases.user1", chroot_env->path_chroot); + add_temp_file (path); + support_write_file_string (path, "alias1\n"); + free (path); + + path = xasprintf ("%s/etc/aliases.user2", chroot_env->path_chroot); + add_temp_file (path); + support_write_file_string (path, "alias1a, alias2\n"); + free (path); + + path = xasprintf ("%s/etc/aliases.comment", chroot_env->path_chroot); + add_temp_file (path); + support_write_file_string + (path, + /* The line must be longer than the line with the :include: + directive in /etc/aliases. */ + "# Long line. ##############################################\n" + "comment2\n"); + free (path); + + path = xasprintf ("%s/etc/aliases.many", chroot_env->path_chroot); + add_temp_file (path); + FILE *fp = xfopen (path, "w"); + for (int i = 0; i < many_aliases; ++i) + fprintf (fp, "a%d\n", i); + TEST_VERIFY_EXIT (! ferror (fp)); + xfclose (fp); + free (path); +} + +/* The names of the users to test. */ +static const char *users[] = { "user1", "user2", "comment", "many" }; + +static void +check_aliases (int id, const struct aliasent *e) +{ + TEST_VERIFY_EXIT (id >= 0 || id < array_length (users)); + const char *name = users[id]; + TEST_COMPARE_BLOB (e->alias_name, strlen (e->alias_name), + name, strlen (name)); + + switch (id) + { + case 0: + TEST_COMPARE (e->alias_members_len, 1); + TEST_COMPARE_BLOB (e->alias_members[0], strlen (e->alias_members[0]), + "alias1", strlen ("alias1")); + break; + + case 1: + TEST_COMPARE (e->alias_members_len, 2); + TEST_COMPARE_BLOB (e->alias_members[0], strlen (e->alias_members[0]), + "alias1a", strlen ("alias1a")); + TEST_COMPARE_BLOB (e->alias_members[1], strlen (e->alias_members[1]), + "alias2", strlen ("alias2")); + break; + + case 2: + TEST_COMPARE (e->alias_members_len, 2); + TEST_COMPARE_BLOB (e->alias_members[0], strlen (e->alias_members[0]), + "comment1", strlen ("comment1")); + TEST_COMPARE_BLOB (e->alias_members[1], strlen (e->alias_members[1]), + "comment2", strlen ("comment2")); + break; + + case 3: + TEST_COMPARE (e->alias_members_len, many_aliases); + for (int i = 0; i < e->alias_members_len; ++i) + { + char alias[30]; + int len = snprintf (alias, sizeof (alias), "a%d", i); + TEST_VERIFY_EXIT (len > 0); + TEST_COMPARE_BLOB (e->alias_members[i], strlen (e->alias_members[i]), + alias, len); + } + break; + } +} + +static int +do_test (void) +{ + /* Make sure we don't try to load the module in the chroot. */ + if (dlopen (LIBNSS_FILES_SO, RTLD_NOW) == NULL) + FAIL_EXIT1 ("could not load " LIBNSS_FILES_SO ": %s", dlerror ()); + + /* Some of these descriptors will become unavailable if there is a + file descriptor leak. 10 is chosen somewhat arbitrarily. The + array must be longer than the number of files opened by nss_files + at the same time (currently that number is 2). */ + int next_descriptors[10]; + for (size_t i = 0; i < array_length (next_descriptors); ++i) + { + next_descriptors[i] = dup (0); + TEST_VERIFY_EXIT (next_descriptors[i] > 0); + } + for (size_t i = 0; i < array_length (next_descriptors); ++i) + xclose (next_descriptors[i]); + + support_become_root (); + if (!support_can_chroot ()) + return EXIT_UNSUPPORTED; + + __nss_configure_lookup ("aliases", "files"); + + xchroot (chroot_env->path_chroot); + + /* Attempt various buffer sizes. If the operation succeeds, we + expect correct data. */ + for (int id = 0; id < array_length (users); ++id) + { + bool found = false; + for (size_t size = 1; size <= 1000; ++size) + { + void *buffer = malloc (size); + struct aliasent result; + struct aliasent *res; + errno = EINVAL; + int ret = getaliasbyname_r (users[id], &result, buffer, size, &res); + if (ret == 0) + { + if (res != NULL) + { + found = true; + check_aliases (id, res); + } + else + { + support_record_failure (); + printf ("error: failed lookup for user \"%s\", size %zu\n", + users[id], size); + } + } + else if (ret != ERANGE) + { + support_record_failure (); + printf ("error: invalid return code %d (user \%s\", size %zu)\n", + ret, users[id], size); + } + free (buffer); + + /* Make sure that we did not have a file descriptor leak. */ + for (size_t i = 0; i < array_length (next_descriptors); ++i) + { + int new_fd = dup (0); + if (new_fd != next_descriptors[i]) + { + support_record_failure (); + printf ("error: descriptor %d at index %zu leaked" + " (user \"%s\", size %zu)\n", + next_descriptors[i], i, users[id], size); + + /* Close unexpected descriptor, the leak probing + descriptors, and the leaked descriptor + next_descriptors[i]. */ + xclose (new_fd); + for (size_t j = 0; j <= i; ++j) + xclose (next_descriptors[j]); + goto next_size; + } + } + for (size_t i = 0; i < array_length (next_descriptors); ++i) + xclose (next_descriptors[i]); + + next_size: + ; + } + if (!found) + { + support_record_failure (); + printf ("error: user %s not found\n", users[id]); + } + } + + support_chroot_free (chroot_env); + return 0; +} + +#define PREPARE prepare +#include diff --git a/posix/Makefile b/posix/Makefile index 00c62841a2..83162123f9 100644 --- a/posix/Makefile +++ b/posix/Makefile @@ -96,7 +96,7 @@ tests := test-errno tstgetopt testfnm runtests runptests \ tst-posix_fadvise tst-posix_fadvise64 \ tst-sysconf-empty-chroot tst-glob_symlinks tst-fexecve \ tst-glob-tilde test-ssize-max tst-spawn4 bug-regex37 \ - bug-regex38 + bug-regex38 tst-regcomp-truncated tests-internal := bug-regex5 bug-regex20 bug-regex33 \ tst-rfc3484 tst-rfc3484-2 tst-rfc3484-3 \ tst-glob_lstat_compat tst-spawn4-compat @@ -194,6 +194,7 @@ $(objpfx)tst-regex2.out: $(gen-locales) $(objpfx)tst-regexloc.out: $(gen-locales) $(objpfx)tst-rxspencer.out: $(gen-locales) $(objpfx)tst-rxspencer-no-utf8.out: $(gen-locales) +$(objpfx)tst-regcomp-truncated.out: $(gen-locales) endif # If we will use the generic uname implementation, we must figure out what diff --git a/posix/regex_internal.c b/posix/regex_internal.c index 7f0083b918..b10588f1cc 100644 --- a/posix/regex_internal.c +++ b/posix/regex_internal.c @@ -317,7 +317,7 @@ build_wcs_upper_buffer (re_string_t *pstr) mbclen = __mbrtowc (&wc, ((const char *) pstr->raw_mbs + pstr->raw_mbs_idx + byte_idx), remain_len, &pstr->cur_state); - if (BE (mbclen < (size_t) -2, 1)) + if (BE (0 < mbclen && mbclen < (size_t) -2, 1)) { wchar_t wcu = __towupper (wc); if (wcu != wc) @@ -386,7 +386,7 @@ build_wcs_upper_buffer (re_string_t *pstr) else p = (const char *) pstr->raw_mbs + pstr->raw_mbs_idx + src_idx; mbclen = __mbrtowc (&wc, p, remain_len, &pstr->cur_state); - if (BE (mbclen < (size_t) -2, 1)) + if (BE (0 < mbclen && mbclen < (size_t) -2, 1)) { wchar_t wcu = __towupper (wc); if (wcu != wc) diff --git a/posix/regexec.c b/posix/regexec.c index 73644c2341..06b8487c3e 100644 --- a/posix/regexec.c +++ b/posix/regexec.c @@ -1289,8 +1289,10 @@ proceed_next_node (const re_match_context_t *mctx, Idx nregs, regmatch_t *regs, else if (naccepted) { char *buf = (char *) re_string_get_buffer (&mctx->input); - if (memcmp (buf + regs[subexp_idx].rm_so, buf + *pidx, - naccepted) != 0) + if (mctx->input.valid_len - *pidx < naccepted + || (memcmp (buf + regs[subexp_idx].rm_so, buf + *pidx, + naccepted) + != 0)) return -1; } } diff --git a/posix/tst-regcomp-truncated.c b/posix/tst-regcomp-truncated.c new file mode 100644 index 0000000000..a4a1581bbc --- /dev/null +++ b/posix/tst-regcomp-truncated.c @@ -0,0 +1,191 @@ +/* Test compilation of truncated regular expressions. + 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 + . */ + +/* This test constructs various patterns in an attempt to trigger + over-reading the regular expression compiler, such as bug + 23578. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Locales to test. */ +static const char locales[][17] = + { + "C", + "en_US.UTF-8", + "de_DE.ISO-8859-1", + }; + +/* Syntax options. Will be combined with other flags. */ +static const reg_syntax_t syntaxes[] = + { + RE_SYNTAX_EMACS, + RE_SYNTAX_AWK, + RE_SYNTAX_GNU_AWK, + RE_SYNTAX_POSIX_AWK, + RE_SYNTAX_GREP, + RE_SYNTAX_EGREP, + RE_SYNTAX_POSIX_EGREP, + RE_SYNTAX_POSIX_BASIC, + RE_SYNTAX_POSIX_EXTENDED, + RE_SYNTAX_POSIX_MINIMAL_EXTENDED, + }; + +/* Trailing characters placed after the initial character. */ +static const char trailing_strings[][4] = + { + "", + "[", + "\\", + "[\\", + "(", + "(\\", + "\\(", + }; + +static int +do_test (void) +{ + /* Staging buffer for the constructed regular expression. */ + char buffer[16]; + + /* Allocation used to detect over-reading by the regular expression + compiler. */ + struct support_next_to_fault ntf + = support_next_to_fault_allocate (sizeof (buffer)); + + /* Arbitrary Unicode codepoint at which we stop generating + characters. We do not probe the whole range because that would + take too long due to combinatorical exploision as the result of + combination with other flags. */ + static const wchar_t last_character = 0xfff; + + for (size_t locale_idx = 0; locale_idx < array_length (locales); + ++ locale_idx) + { + if (setlocale (LC_ALL, locales[locale_idx]) == NULL) + { + support_record_failure (); + printf ("error: setlocale (\"%s\"): %m", locales[locale_idx]); + continue; + } + if (test_verbose > 0) + printf ("info: testing locale \"%s\"\n", locales[locale_idx]); + + for (wchar_t wc = 0; wc <= last_character; ++wc) + { + char *after_wc; + if (wc == 0) + { + /* wcrtomb treats L'\0' in a special way. */ + *buffer = '\0'; + after_wc = &buffer[1]; + } + else + { + mbstate_t ps = { }; + size_t ret = wcrtomb (buffer, wc, &ps); + if (ret == (size_t) -1) + { + /* EILSEQ means that the target character set + cannot encode the character. */ + if (errno != EILSEQ) + { + support_record_failure (); + printf ("error: wcrtomb (0x%x) failed: %m\n", + (unsigned) wc); + } + continue; + } + TEST_VERIFY_EXIT (ret != 0); + after_wc = &buffer[ret]; + } + + for (size_t trailing_idx = 0; + trailing_idx < array_length (trailing_strings); + ++trailing_idx) + { + char *after_trailing + = stpcpy (after_wc, trailing_strings[trailing_idx]); + + for (int do_nul = 0; do_nul < 2; ++do_nul) + { + char *after_nul; + if (do_nul) + { + *after_trailing = '\0'; + after_nul = &after_trailing[1]; + } + else + after_nul = after_trailing; + + size_t length = after_nul - buffer; + + /* Make sure that the faulting region starts + after the used portion of the buffer. */ + char *ntf_start = ntf.buffer + sizeof (buffer) - length; + memcpy (ntf_start, buffer, length); + + for (const reg_syntax_t *psyntax = syntaxes; + psyntax < array_end (syntaxes); ++psyntax) + for (int do_icase = 0; do_icase < 2; ++do_icase) + { + re_syntax_options = *psyntax; + if (do_icase) + re_syntax_options |= RE_ICASE; + + regex_t reg; + memset (®, 0, sizeof (reg)); + const char *msg = re_compile_pattern + (ntf_start, length, ®); + if (msg != NULL) + { + if (test_verbose > 0) + { + char *quoted = support_quote_blob + (buffer, length); + printf ("info: compilation failed for pattern" + " \"%s\", syntax 0x%lx: %s\n", + quoted, re_syntax_options, msg); + free (quoted); + } + } + else + regfree (®); + } + } + } + } + } + + support_next_to_fault_free (&ntf); + + return 0; +} + +#include diff --git a/resolv/Makefile b/resolv/Makefile index ea395ac3eb..d36eedd34a 100644 --- a/resolv/Makefile +++ b/resolv/Makefile @@ -34,6 +34,9 @@ routines := herror inet_addr inet_ntop inet_pton nsap_addr res_init \ tests = tst-aton tst-leaks tst-inet_ntop xtests = tst-leaks2 +tests-internal += tst-inet_aton_exact + + generate := mtrace-tst-leaks.out tst-leaks.mtrace tst-leaks2.mtrace extra-libs := libresolv libnss_dns @@ -54,8 +57,10 @@ tests += \ tst-resolv-binary \ tst-resolv-edns \ tst-resolv-network \ + tst-resolv-nondecimal \ tst-resolv-res_init-multi \ tst-resolv-search \ + tst-resolv-trailing \ # These tests need libdl. ifeq (yes,$(build-shared)) @@ -190,9 +195,11 @@ $(objpfx)tst-resolv-res_init-multi: $(objpfx)libresolv.so \ $(shared-thread-library) $(objpfx)tst-resolv-res_init-thread: $(libdl) $(objpfx)libresolv.so \ $(shared-thread-library) +$(objpfx)tst-resolv-nondecimal: $(objpfx)libresolv.so $(shared-thread-library) $(objpfx)tst-resolv-qtypes: $(objpfx)libresolv.so $(shared-thread-library) $(objpfx)tst-resolv-rotate: $(objpfx)libresolv.so $(shared-thread-library) $(objpfx)tst-resolv-search: $(objpfx)libresolv.so $(shared-thread-library) +$(objpfx)tst-resolv-trailing: $(objpfx)libresolv.so $(shared-thread-library) $(objpfx)tst-resolv-threads: \ $(libdl) $(objpfx)libresolv.so $(shared-thread-library) $(objpfx)tst-resolv-canonname: \ diff --git a/resolv/Versions b/resolv/Versions index b05778d965..9a82704af7 100644 --- a/resolv/Versions +++ b/resolv/Versions @@ -27,6 +27,7 @@ libc { __h_errno; __resp; __res_iclose; + __inet_aton_exact; __inet_pton_length; __resolv_context_get; __resolv_context_get_preinit; diff --git a/resolv/gai_misc.c b/resolv/gai_misc.c index e7c3b63cc5..80a2cff835 100644 --- a/resolv/gai_misc.c +++ b/resolv/gai_misc.c @@ -261,8 +261,11 @@ __gai_enqueue_request (struct gaicb *gaicbp) /* We cannot create a thread in the moment and there is also no thread running. This is a problem. `errno' is set to EAGAIN if this is only a temporary problem. */ - assert (lastp->next == newp); - lastp->next = NULL; + assert (requests == newp || lastp->next == newp); + if (lastp != NULL) + lastp->next = NULL; + else + requests = NULL; requests_tail = lastp; newp->next = freelist; diff --git a/resolv/inet_addr.c b/resolv/inet_addr.c index 022f7ea084..41b6166a5b 100644 --- a/resolv/inet_addr.c +++ b/resolv/inet_addr.c @@ -1,3 +1,21 @@ +/* Legacy IPv4 text-to-address functions. + Copyright (C) 2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + /* * Copyright (c) 1983, 1990, 1993 * The Regents of the University of California. All rights reserved. @@ -78,106 +96,122 @@ #include #include -/* - * Ascii internet address interpretation routine. - * The value returned is in network order. - */ -in_addr_t -__inet_addr(const char *cp) { - struct in_addr val; - - if (__inet_aton(cp, &val)) - return (val.s_addr); - return (INADDR_NONE); +/* Check whether "cp" is a valid ASCII representation of an IPv4 + Internet address and convert it to a binary address. Returns 1 if + the address is valid, 0 if not. This replaces inet_addr, the + return value from which cannot distinguish between failure and a + local broadcast address. Write a pointer to the first + non-converted character to *endp. */ +static int +inet_aton_end (const char *cp, struct in_addr *addr, const char **endp) +{ + static const in_addr_t max[4] = { 0xffffffff, 0xffffff, 0xffff, 0xff }; + in_addr_t val; + char c; + union iaddr + { + uint8_t bytes[4]; + uint32_t word; + } res; + uint8_t *pp = res.bytes; + int digit; + + int saved_errno = errno; + __set_errno (0); + + res.word = 0; + + c = *cp; + for (;;) + { + /* Collect number up to ``.''. Values are specified as for C: + 0x=hex, 0=octal, isdigit=decimal. */ + if (!isdigit (c)) + goto ret_0; + { + char *endp; + unsigned long ul = strtoul (cp, &endp, 0); + if (ul == ULONG_MAX && errno == ERANGE) + goto ret_0; + if (ul > 0xfffffffful) + goto ret_0; + val = ul; + digit = cp != endp; + cp = endp; + } + c = *cp; + if (c == '.') + { + /* Internet format: + a.b.c.d + a.b.c (with c treated as 16 bits) + a.b (with b treated as 24 bits). */ + if (pp > res.bytes + 2 || val > 0xff) + goto ret_0; + *pp++ = val; + c = *++cp; + } + else + break; + } + /* Check for trailing characters. */ + if (c != '\0' && (!isascii (c) || !isspace (c))) + goto ret_0; + /* Did we get a valid digit? */ + if (!digit) + goto ret_0; + + /* Check whether the last part is in its limits depending on the + number of parts in total. */ + if (val > max[pp - res.bytes]) + goto ret_0; + + if (addr != NULL) + addr->s_addr = res.word | htonl (val); + *endp = cp; + + __set_errno (saved_errno); + return 1; + + ret_0: + __set_errno (saved_errno); + return 0; } -weak_alias (__inet_addr, inet_addr) -/* - * Check whether "cp" is a valid ascii representation - * of an Internet address and convert to a binary address. - * Returns 1 if the address is valid, 0 if not. - * This replaces inet_addr, the return value from which - * cannot distinguish between failure and a local broadcast address. - */ int -__inet_aton(const char *cp, struct in_addr *addr) +__inet_aton_exact (const char *cp, struct in_addr *addr) { - static const in_addr_t max[4] = { 0xffffffff, 0xffffff, 0xffff, 0xff }; - in_addr_t val; - char c; - union iaddr { - uint8_t bytes[4]; - uint32_t word; - } res; - uint8_t *pp = res.bytes; - int digit; - - int saved_errno = errno; - __set_errno (0); - - res.word = 0; - - c = *cp; - for (;;) { - /* - * Collect number up to ``.''. - * Values are specified as for C: - * 0x=hex, 0=octal, isdigit=decimal. - */ - if (!isdigit(c)) - goto ret_0; - { - char *endp; - unsigned long ul = strtoul (cp, (char **) &endp, 0); - if (ul == ULONG_MAX && errno == ERANGE) - goto ret_0; - if (ul > 0xfffffffful) - goto ret_0; - val = ul; - digit = cp != endp; - cp = endp; - } - c = *cp; - if (c == '.') { - /* - * Internet format: - * a.b.c.d - * a.b.c (with c treated as 16 bits) - * a.b (with b treated as 24 bits) - */ - if (pp > res.bytes + 2 || val > 0xff) - goto ret_0; - *pp++ = val; - c = *++cp; - } else - break; - } - /* - * Check for trailing characters. - */ - if (c != '\0' && (!isascii(c) || !isspace(c))) - goto ret_0; - /* - * Did we get a valid digit? - */ - if (!digit) - goto ret_0; - - /* Check whether the last part is in its limits depending on - the number of parts in total. */ - if (val > max[pp - res.bytes]) - goto ret_0; - - if (addr != NULL) - addr->s_addr = res.word | htonl (val); + struct in_addr val; + const char *endp; + /* Check that inet_aton_end parsed the entire string. */ + if (inet_aton_end (cp, &val, &endp) != 0 && *endp == 0) + { + *addr = val; + return 1; + } + else + return 0; +} +libc_hidden_def (__inet_aton_exact) - __set_errno (saved_errno); - return (1); +/* inet_aton ignores trailing garbage. */ +int +__inet_aton_ignore_trailing (const char *cp, struct in_addr *addr) +{ + const char *endp; + return inet_aton_end (cp, addr, &endp); +} +weak_alias (__inet_aton_ignore_trailing, inet_aton) -ret_0: - __set_errno (saved_errno); - return (0); +/* ASCII IPv4 Internet address interpretation routine. The value + returned is in network order. */ +in_addr_t +__inet_addr (const char *cp) +{ + struct in_addr val; + const char *endp; + if (inet_aton_end (cp, &val, &endp)) + return val.s_addr; + return INADDR_NONE; } -weak_alias (__inet_aton, inet_aton) -libc_hidden_def (__inet_aton) -libc_hidden_weak (inet_aton) +weak_alias (__inet_addr, inet_addr) diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c index 5dc2829cd1..99c3b61e1c 100644 --- a/resolv/nss_dns/dns-host.c +++ b/resolv/nss_dns/dns-host.c @@ -274,11 +274,26 @@ gethostbyname3_context (struct resolv_context *ctx, return status; } +/* Verify that the name looks like a host name. There is no point in + sending a query which will not produce a usable name in the + response. */ +static enum nss_status +check_name (const char *name, int *h_errnop) +{ + if (res_hnok (name)) + return NSS_STATUS_SUCCESS; + *h_errnop = HOST_NOT_FOUND; + return NSS_STATUS_NOTFOUND; +} + enum nss_status _nss_dns_gethostbyname2_r (const char *name, int af, struct hostent *result, char *buffer, size_t buflen, int *errnop, int *h_errnop) { + enum nss_status status = check_name (name, h_errnop); + if (status != NSS_STATUS_SUCCESS) + return status; return _nss_dns_gethostbyname3_r (name, af, result, buffer, buflen, errnop, h_errnop, NULL, NULL); } @@ -289,6 +304,9 @@ _nss_dns_gethostbyname_r (const char *name, struct hostent *result, char *buffer, size_t buflen, int *errnop, int *h_errnop) { + enum nss_status status = check_name (name, h_errnop); + if (status != NSS_STATUS_SUCCESS) + return status; struct resolv_context *ctx = __resolv_context_get (); if (ctx == NULL) { @@ -296,7 +314,7 @@ _nss_dns_gethostbyname_r (const char *name, struct hostent *result, *h_errnop = NETDB_INTERNAL; return NSS_STATUS_UNAVAIL; } - enum nss_status status = NSS_STATUS_NOTFOUND; + status = NSS_STATUS_NOTFOUND; if (res_use_inet6 ()) status = gethostbyname3_context (ctx, name, AF_INET6, result, buffer, buflen, errnop, h_errnop, NULL, NULL); @@ -313,6 +331,9 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, char *buffer, size_t buflen, int *errnop, int *herrnop, int32_t *ttlp) { + enum nss_status status = check_name (name, herrnop); + if (status != NSS_STATUS_SUCCESS) + return status; struct resolv_context *ctx = __resolv_context_get (); if (ctx == NULL) { @@ -347,7 +368,6 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, int ans2p_malloced = 0; int olderr = errno; - enum nss_status status; int n = __res_context_search (ctx, name, C_IN, T_QUERY_A_AND_AAAA, host_buffer.buf->buf, 2048, &host_buffer.ptr, &ans2p, &nans2p, &resplen2, &ans2p_malloced); diff --git a/resolv/res_init.c b/resolv/res_init.c index f5e52cbbb9..94743a252e 100644 --- a/resolv/res_init.c +++ b/resolv/res_init.c @@ -399,8 +399,16 @@ res_vinit_1 (FILE *fp, struct resolv_conf_parser *parser) cp = parser->buffer + sizeof ("nameserver") - 1; while (*cp == ' ' || *cp == '\t') cp++; + + /* Ignore trailing contents on the name server line. */ + { + char *el; + if ((el = strpbrk (cp, " \t\n")) != NULL) + *el = '\0'; + } + struct sockaddr *sa; - if ((*cp != '\0') && (*cp != '\n') && __inet_aton (cp, &a)) + if ((*cp != '\0') && (*cp != '\n') && __inet_aton_exact (cp, &a)) { sa = allocate_address_v4 (a, NAMESERVER_PORT); if (sa == NULL) @@ -410,9 +418,6 @@ res_vinit_1 (FILE *fp, struct resolv_conf_parser *parser) { struct in6_addr a6; char *el; - - if ((el = strpbrk (cp, " \t\n")) != NULL) - *el = '\0'; if ((el = strchr (cp, SCOPE_DELIMITER)) != NULL) *el = '\0'; if ((*cp != '\0') && (__inet_pton (AF_INET6, cp, &a6) > 0)) @@ -472,7 +477,7 @@ res_vinit_1 (FILE *fp, struct resolv_conf_parser *parser) char separator = *cp; *cp = 0; struct resolv_sortlist_entry e; - if (__inet_aton (net, &a)) + if (__inet_aton_exact (net, &a)) { e.addr = a; if (is_sort_mask (separator)) @@ -484,7 +489,7 @@ res_vinit_1 (FILE *fp, struct resolv_conf_parser *parser) cp++; separator = *cp; *cp = 0; - if (__inet_aton (net, &a)) + if (__inet_aton_exact (net, &a)) e.mask = a.s_addr; else e.mask = net_mask (e.addr); diff --git a/resolv/tst-aton.c b/resolv/tst-aton.c index 08110a007a..eb734d7758 100644 --- a/resolv/tst-aton.c +++ b/resolv/tst-aton.c @@ -1,11 +1,29 @@ +/* Test legacy IPv4 text-to-address function inet_aton. + Copyright (C) 1998-2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for 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 struct tests +static const struct tests { const char *input; int valid; @@ -16,6 +34,7 @@ static struct tests { "-1", 0, 0 }, { "256", 1, 0x00000100 }, { "256.", 0, 0 }, + { "255a", 0, 0 }, { "256a", 0, 0 }, { "0x100", 1, 0x00000100 }, { "0200.0x123456", 1, 0x80123456 }, @@ -40,7 +59,12 @@ static struct tests { "1.2.256.4", 0, 0 }, { "1.2.3.0x100", 0, 0 }, { "323543357756889", 0, 0 }, - { "10.1.2.3.4", 0, 0}, + { "10.1.2.3.4", 0, 0 }, + { "192.0.2.1", 1, 0xc0000201 }, + { "192.0.2.2\nX", 1, 0xc0000202 }, + { "192.0.2.3 Y", 1, 0xc0000203 }, + { "192.0.2.3Z", 0, 0 }, + { "192.000.002.010", 1, 0xc0000208 }, }; @@ -50,7 +74,7 @@ do_test (void) int result = 0; size_t cnt; - for (cnt = 0; cnt < sizeof (tests) / sizeof (tests[0]); ++cnt) + for (cnt = 0; cnt < array_length (tests); ++cnt) { struct in_addr addr; @@ -73,5 +97,4 @@ do_test (void) return result; } -#define TEST_FUNCTION do_test () -#include "../test-skeleton.c" +#include diff --git a/resolv/tst-inet_aton_exact.c b/resolv/tst-inet_aton_exact.c new file mode 100644 index 0000000000..0fdfa3d6aa --- /dev/null +++ b/resolv/tst-inet_aton_exact.c @@ -0,0 +1,47 @@ +/* Test internal legacy IPv4 text-to-address function __inet_aton_exact. + Copyright (C) 2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for 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) +{ + struct in_addr addr = { }; + + TEST_COMPARE (__inet_aton_exact ("192.0.2.1", &addr), 1); + TEST_COMPARE (ntohl (addr.s_addr), 0xC0000201); + + TEST_COMPARE (__inet_aton_exact ("192.000.002.010", &addr), 1); + TEST_COMPARE (ntohl (addr.s_addr), 0xC0000208); + TEST_COMPARE (__inet_aton_exact ("0xC0000234", &addr), 1); + TEST_COMPARE (ntohl (addr.s_addr), 0xC0000234); + + /* Trailing content is not accepted. */ + TEST_COMPARE (__inet_aton_exact ("192.0.2.2X", &addr), 0); + TEST_COMPARE (__inet_aton_exact ("192.0.2.3 Y", &addr), 0); + TEST_COMPARE (__inet_aton_exact ("192.0.2.4\nZ", &addr), 0); + TEST_COMPARE (__inet_aton_exact ("192.0.2.5\tT", &addr), 0); + TEST_COMPARE (__inet_aton_exact ("192.0.2.6 Y", &addr), 0); + TEST_COMPARE (__inet_aton_exact ("192.0.2.7\n", &addr), 0); + TEST_COMPARE (__inet_aton_exact ("192.0.2.8\t", &addr), 0); + + return 0; +} + +#include diff --git a/resolv/tst-resolv-network.c b/resolv/tst-resolv-network.c index 4b862d57e6..735e38d0f8 100644 --- a/resolv/tst-resolv-network.c +++ b/resolv/tst-resolv-network.c @@ -149,6 +149,9 @@ handle_code (const struct resolv_response_context *ctx, resolv_response_add_data (b, &rrtype, sizeof (rrtype)); } break; + case 104: + send_ptr (b, qname, qclass, qtype, "host.example"); + break; default: FAIL_EXIT1 ("invalid QNAME: %s (code %d)", qname, code); } @@ -257,6 +260,9 @@ do_test (void) "error: TRY_AGAIN\n"); check_netent ("code103.example", getnetbyname ("code103.example"), "error: NO_RECOVERY\n"); + /* Test bug #17630. */ + check_netent ("code104.example", getnetbyname ("code104.example"), + "error: TRY_AGAIN\n"); /* Lookup by address, success cases. */ check_reverse (1, diff --git a/resolv/tst-resolv-nondecimal.c b/resolv/tst-resolv-nondecimal.c new file mode 100644 index 0000000000..a0df6f332a --- /dev/null +++ b/resolv/tst-resolv-nondecimal.c @@ -0,0 +1,139 @@ +/* Test name resolution behavior for octal, hexadecimal IPv4 addresses. + Copyright (C) 2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for 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 +response (const struct resolv_response_context *ctx, + struct resolv_response_builder *b, + const char *qname, uint16_t qclass, uint16_t qtype) +{ + /* The tests are not supposed send any DNS queries. */ + FAIL_EXIT1 ("unexpected DNS query for %s/%d/%d", qname, qclass, qtype); +} + +static void +run_query_addrinfo (const char *query, const char *address) +{ + char *quoted_query = support_quote_string (query); + + struct addrinfo *ai; + struct addrinfo hints = + { + .ai_socktype = SOCK_STREAM, + .ai_protocol = IPPROTO_TCP, + }; + + char *context = xasprintf ("getaddrinfo \"%s\" AF_INET", quoted_query); + char *expected = xasprintf ("address: STREAM/TCP %s 80\n", address); + hints.ai_family = AF_INET; + int ret = getaddrinfo (query, "80", &hints, &ai); + check_addrinfo (context, ai, ret, expected); + if (ret == 0) + freeaddrinfo (ai); + free (context); + + context = xasprintf ("getaddrinfo \"%s\" AF_UNSPEC", quoted_query); + hints.ai_family = AF_UNSPEC; + ret = getaddrinfo (query, "80", &hints, &ai); + check_addrinfo (context, ai, ret, expected); + if (ret == 0) + freeaddrinfo (ai); + free (expected); + free (context); + + context = xasprintf ("getaddrinfo \"%s\" AF_INET6", quoted_query); + expected = xasprintf ("flags: AI_V4MAPPED\n" + "address: STREAM/TCP ::ffff:%s 80\n", + address); + hints.ai_family = AF_INET6; + hints.ai_flags = AI_V4MAPPED; + ret = getaddrinfo (query, "80", &hints, &ai); + check_addrinfo (context, ai, ret, expected); + if (ret == 0) + freeaddrinfo (ai); + free (expected); + free (context); + + free (quoted_query); +} + +static void +run_query (const char *query, const char *address) +{ + char *quoted_query = support_quote_string (query); + char *context = xasprintf ("gethostbyname (\"%s\")", quoted_query); + char *expected = xasprintf ("name: %s\n" + "address: %s\n", query, address); + check_hostent (context, gethostbyname (query), expected); + free (context); + + context = xasprintf ("gethostbyname_r \"%s\"", quoted_query); + struct hostent storage; + char buf[4096]; + struct hostent *e = NULL; + TEST_COMPARE (gethostbyname_r (query, &storage, buf, sizeof (buf), + &e, &h_errno), 0); + check_hostent (context, e, expected); + free (context); + + context = xasprintf ("gethostbyname2 (\"%s\", AF_INET)", quoted_query); + check_hostent (context, gethostbyname2 (query, AF_INET), expected); + free (context); + + context = xasprintf ("gethostbyname2_r \"%s\" AF_INET", quoted_query); + e = NULL; + TEST_COMPARE (gethostbyname2_r (query, AF_INET, &storage, buf, sizeof (buf), + &e, &h_errno), 0); + check_hostent (context, e, expected); + free (context); + free (expected); + + free (quoted_query); + + /* The gethostbyname tests are always valid for getaddrinfo, but not + vice versa. */ + run_query_addrinfo (query, address); +} + +static int +do_test (void) +{ + struct resolv_test *aux = resolv_test_start + ((struct resolv_redirect_config) + { + .response_callback = response, + }); + + run_query ("192.000.002.010", "192.0.2.8"); + + /* Hexadecimal numbers are not accepted by gethostbyname. */ + run_query_addrinfo ("0xc0000210", "192.0.2.16"); + run_query_addrinfo ("192.0x234", "192.0.2.52"); + + resolv_test_end (aux); + + return 0; +} + +#include diff --git a/resolv/tst-resolv-trailing.c b/resolv/tst-resolv-trailing.c new file mode 100644 index 0000000000..7504bdae57 --- /dev/null +++ b/resolv/tst-resolv-trailing.c @@ -0,0 +1,136 @@ +/* Test name resolution behavior with trailing characters. + Copyright (C) 2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for 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 +response (const struct resolv_response_context *ctx, + struct resolv_response_builder *b, + const char *qname, uint16_t qclass, uint16_t qtype) +{ + /* The tests are not supposed send any DNS queries. */ + FAIL_EXIT1 ("unexpected DNS query for %s/%d/%d", qname, qclass, qtype); +} + +static int +do_test (void) +{ + struct resolv_test *aux = resolv_test_start + ((struct resolv_redirect_config) + { + .response_callback = response, + }); + + static const char *const queries[] = + { + "192.0.2.1 ", + "192.0.2.2\t", + "192.0.2.3\n", + "192.0.2.4 X", + "192.0.2.5\tY", + "192.0.2.6\nZ", + "192.0.2. ", + "192.0.2.\t", + "192.0.2.\n", + "192.0.2. X", + "192.0.2.\tY", + "192.0.2.\nZ", + "2001:db8::1 ", + "2001:db8::2\t", + "2001:db8::3\n", + "2001:db8::4 X", + "2001:db8::5\tY", + "2001:db8::6\nZ", + }; + for (size_t query_idx = 0; query_idx < array_length (queries); ++query_idx) + { + const char *query = queries[query_idx]; + struct hostent storage; + char buf[4096]; + struct hostent *e; + + h_errno = 0; + TEST_VERIFY (gethostbyname (query) == NULL); + TEST_COMPARE (h_errno, HOST_NOT_FOUND); + + h_errno = 0; + e = NULL; + TEST_COMPARE (gethostbyname_r (query, &storage, buf, sizeof (buf), + &e, &h_errno), 0); + TEST_VERIFY (e == NULL); + TEST_COMPARE (h_errno, HOST_NOT_FOUND); + + h_errno = 0; + TEST_VERIFY (gethostbyname2 (query, AF_INET) == NULL); + TEST_COMPARE (h_errno, HOST_NOT_FOUND); + + h_errno = 0; + e = NULL; + TEST_COMPARE (gethostbyname2_r (query, AF_INET, + &storage, buf, sizeof (buf), + &e, &h_errno), 0); + TEST_VERIFY (e == NULL); + TEST_COMPARE (h_errno, HOST_NOT_FOUND); + + h_errno = 0; + TEST_VERIFY (gethostbyname2 (query, AF_INET6) == NULL); + TEST_COMPARE (h_errno, HOST_NOT_FOUND); + + h_errno = 0; + e = NULL; + TEST_COMPARE (gethostbyname2_r (query, AF_INET6, + &storage, buf, sizeof (buf), + &e, &h_errno), 0); + TEST_VERIFY (e == NULL); + TEST_COMPARE (h_errno, HOST_NOT_FOUND); + + static const int gai_flags[] = + { + 0, + AI_ADDRCONFIG, + AI_NUMERICHOST, + AI_IDN, + AI_IDN | AI_NUMERICHOST, + AI_V4MAPPED, + AI_V4MAPPED | AI_NUMERICHOST, + }; + for (size_t gai_flags_idx; gai_flags_idx < array_length (gai_flags); + ++gai_flags_idx) + { + struct addrinfo hints = { .ai_flags = gai_flags[gai_flags_idx], }; + struct addrinfo *ai; + hints.ai_family = AF_INET; + TEST_COMPARE (getaddrinfo (query, "80", &hints, &ai), EAI_NONAME); + hints.ai_family = AF_INET6; + TEST_COMPARE (getaddrinfo (query, "80", &hints, &ai), EAI_NONAME); + hints.ai_family = AF_UNSPEC; + TEST_COMPARE (getaddrinfo (query, "80", &hints, &ai), EAI_NONAME); + } + }; + + resolv_test_end (aux); + + return 0; +} + +#include diff --git a/stdlib/test-bz22786.c b/stdlib/test-bz22786.c index e7837f98c1..8035e8a394 100644 --- a/stdlib/test-bz22786.c +++ b/stdlib/test-bz22786.c @@ -26,49 +26,39 @@ #include #include #include +#include +#include +#include +#include #include #include static int do_test (void) { - const char dir[] = "bz22786"; - const char lnk[] = "bz22786/symlink"; - - rmdir (dir); - if (mkdir (dir, 0755) != 0 && errno != EEXIST) - { - printf ("mkdir %s: %m\n", dir); - return EXIT_FAILURE; - } - if (symlink (".", lnk) != 0 && errno != EEXIST) - { - printf ("symlink (%s, %s): %m\n", dir, lnk); - return EXIT_FAILURE; - } - - const size_t path_len = (size_t) INT_MAX + 1; - - DIAG_PUSH_NEEDS_COMMENT; -#if __GNUC_PREREQ (7, 0) - /* GCC 7 warns about too-large allocations; here we need such - allocation to succeed for the test to work. */ - DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than="); -#endif - char *path = malloc (path_len); - DIAG_POP_NEEDS_COMMENT; + char *dir = support_create_temp_directory ("bz22786."); + char *lnk = xasprintf ("%s/symlink", dir); + const size_t path_len = (size_t) INT_MAX + strlen (lnk) + 1; + struct support_blob_repeat repeat + = support_blob_repeat_allocate ("a", 1, path_len); + char *path = repeat.start; if (path == NULL) { - printf ("malloc (%zu): %m\n", path_len); + printf ("Repeated allocation (%zu bytes): %m\n", path_len); + /* On 31-bit s390 the malloc will always fail as we do not have + so much memory, and we want to mark the test unsupported. + Likewise on systems with little physical memory the test will + fail and should be unsupported. */ return EXIT_UNSUPPORTED; } - /* Construct very long path = "bz22786/symlink/aaaa....." */ - char *p = mempcpy (path, lnk, sizeof (lnk) - 1); + TEST_VERIFY_EXIT (symlink (".", lnk) == 0); + + /* Construct very long path = "/tmp/bz22786.XXXX/symlink/aaaa....." */ + char *p = mempcpy (path, lnk, strlen (lnk)); *(p++) = '/'; - memset (p, 'a', path_len - (path - p) - 2); - p[path_len - (path - p) - 1] = '\0'; + p[path_len - (p - path) - 1] = '\0'; /* This call crashes before the fix for bz22786 on 32-bit platforms. */ p = realpath (path, NULL); @@ -81,7 +71,9 @@ do_test (void) /* Cleanup. */ unlink (lnk); - rmdir (dir); + support_blob_repeat_free (&repeat); + free (lnk); + free (dir); return 0; } diff --git a/stdlib/tst-setcontext9.c b/stdlib/tst-setcontext9.c index 4636ce9030..009928235d 100644 --- a/stdlib/tst-setcontext9.c +++ b/stdlib/tst-setcontext9.c @@ -41,30 +41,59 @@ f2 (void) } static void -f1 (void) +f1b (void) { - puts ("start f1"); - if (getcontext (&ctx[2]) != 0) - { - printf ("%s: getcontext: %m\n", __FUNCTION__); - exit (EXIT_FAILURE); - } if (done) { - puts ("set context in f1"); + puts ("set context in f1b"); if (setcontext (&ctx[3]) != 0) { printf ("%s: setcontext: %m\n", __FUNCTION__); exit (EXIT_FAILURE); } } + exit (EXIT_FAILURE); +} + +static void +f1a (void) +{ + static char st2[32768]; + puts ("start f1a"); + if (getcontext (&ctx[2]) != 0) + { + printf ("%s: getcontext: %m\n", __FUNCTION__); + exit (EXIT_FAILURE); + } + ctx[2].uc_stack.ss_sp = st2; + ctx[2].uc_stack.ss_size = sizeof st2; + ctx[2].uc_link = &ctx[0]; + makecontext (&ctx[2], (void (*) (void)) f1b, 0); f2 (); } +/* The execution path through the test looks like this: + do_test (call) + -> "making contexts" + -> "swap contexts" + f1a (via swapcontext to ctx[1], with alternate stack) + -> "start f1a" + f2 (call) + -> "swap contexts in f2" + f1b (via swapcontext to ctx[2], with alternate stack) + -> "set context in f1b" + do_test (via setcontext to ctx[3], main stack) + -> "setcontext" + f2 (via setcontext to ctx[4], with alternate stack) + -> "end f2" + + We must use an alternate stack for f1b, because if we don't then the + result of executing an earlier caller may overwrite registers + spilled to the stack in f2. */ static int do_test (void) { - char st1[32768]; + static char st1[32768]; puts ("making contexts"); if (getcontext (&ctx[0]) != 0) { @@ -79,7 +108,7 @@ do_test (void) ctx[1].uc_stack.ss_sp = st1; ctx[1].uc_stack.ss_size = sizeof st1; ctx[1].uc_link = &ctx[0]; - makecontext (&ctx[1], (void (*) (void)) f1, 0); + makecontext (&ctx[1], (void (*) (void)) f1a, 0); puts ("swap contexts"); if (swapcontext (&ctx[3], &ctx[1]) != 0) { diff --git a/stdlib/tst-strtod-overflow.c b/stdlib/tst-strtod-overflow.c index d14638d68e..dc53c1e521 100644 --- a/stdlib/tst-strtod-overflow.c +++ b/stdlib/tst-strtod-overflow.c @@ -19,6 +19,8 @@ #include #include #include +#include +#include #define EXPONENT "e-2147483649" #define SIZE 214748364 @@ -26,21 +28,23 @@ static int do_test (void) { - char *p = malloc (1 + SIZE + sizeof (EXPONENT)); - if (p == NULL) + struct support_blob_repeat repeat = support_blob_repeat_allocate + ("0", 1, 1 + SIZE + sizeof (EXPONENT)); + if (repeat.size == 0) { - puts ("malloc failed, cannot test for overflow"); - return 0; + puts ("warning: memory allocation failed, cannot test for overflow"); + return EXIT_UNSUPPORTED; } + char *p = repeat.start; p[0] = '1'; - memset (p + 1, '0', SIZE); memcpy (p + 1 + SIZE, EXPONENT, sizeof (EXPONENT)); double d = strtod (p, NULL); if (d != 0) { - printf ("strtod returned wrong value: %a\n", d); + printf ("error: strtod returned wrong value: %a\n", d); return 1; } + support_blob_repeat_free (&repeat); return 0; } diff --git a/string/Makefile b/string/Makefile index 680431f921..aa2da9ca72 100644 --- a/string/Makefile +++ b/string/Makefile @@ -64,6 +64,12 @@ tests := tester inl-tester noinl-tester testcopy test-ffs \ # This test allocates a lot of memory and can run for a long time. xtests = tst-strcoll-overflow +# This test needs libdl. +ifeq (yes,$(build-shared)) +tests += test-strerror-errno +LDLIBS-test-strerror-errno = $(libdl) +endif + ifeq ($(run-built-tests),yes) tests-special += $(objpfx)tst-svc-cmp.out endif diff --git a/string/strcasestr.c b/string/strcasestr.c index 5909fe3cdb..421764bd1b 100644 --- a/string/strcasestr.c +++ b/string/strcasestr.c @@ -37,8 +37,9 @@ /* Two-Way algorithm. */ #define RETURN_TYPE char * #define AVAILABLE(h, h_l, j, n_l) \ - (((j) + (n_l) <= (h_l)) || ((h_l) += __strnlen ((void*)((h) + (h_l)), 512), \ - (j) + (n_l) <= (h_l))) + (((j) + (n_l) <= (h_l)) \ + || ((h_l) += __strnlen ((void*)((h) + (h_l)), (n_l) + 512), \ + (j) + (n_l) <= (h_l))) #define CHECK_EOL (1) #define RET0_IF_0(a) if (!a) goto ret0 #define CANON_ELEMENT(c) TOLOWER (c) diff --git a/string/strstr.c b/string/strstr.c index 265e9f310c..79ebcc7532 100644 --- a/string/strstr.c +++ b/string/strstr.c @@ -33,8 +33,9 @@ #define RETURN_TYPE char * #define AVAILABLE(h, h_l, j, n_l) \ - (((j) + (n_l) <= (h_l)) || ((h_l) += __strnlen ((void*)((h) + (h_l)), 512), \ - (j) + (n_l) <= (h_l))) + (((j) + (n_l) <= (h_l)) \ + || ((h_l) += __strnlen ((void*)((h) + (h_l)), (n_l) + 512), \ + (j) + (n_l) <= (h_l))) #define CHECK_EOL (1) #define RET0_IF_0(a) if (!a) goto ret0 #define FASTSEARCH(S,C,N) (void*) strchr ((void*)(S), (C)) diff --git a/string/test-strerror-errno.c b/string/test-strerror-errno.c new file mode 100644 index 0000000000..8e744e7ed9 --- /dev/null +++ b/string/test-strerror-errno.c @@ -0,0 +1,61 @@ +/* BZ #24024 strerror and errno test. + + Copyright (C) 2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for 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 + +/* malloc is allowed to change errno to a value different than 0, even when + there is no actual error. This happens for example when the memory + allocation through sbrk fails. Simulate this by interposing our own + malloc implementation which sets errno to ENOMEM and calls the original + malloc. */ +void +*malloc (size_t size) +{ + static void *(*real_malloc) (size_t size); + + if (!real_malloc) + real_malloc = dlsym (RTLD_NEXT, "malloc"); + + errno = ENOMEM; + + return (*real_malloc) (size); +} + +/* strerror must not change the value of errno. Unfortunately due to GCC bug + #88576, this happens when -fmath-errno is used. This simple test checks + that it doesn't happen. */ +static int +do_test (void) +{ + char *msg; + + errno = 0; + msg = strerror (-3); + (void) msg; + TEST_COMPARE (errno, 0); + + return 0; +} + +#include diff --git a/string/test-strstr.c b/string/test-strstr.c index 8d99716ff3..5861b01b73 100644 --- a/string/test-strstr.c +++ b/string/test-strstr.c @@ -151,6 +151,32 @@ check2 (void) } } +#define N 1024 + +static void +pr23637 (void) +{ + char *h = (char*) buf1; + char *n = (char*) buf2; + + for (int i = 0; i < N; i++) + { + n[i] = 'x'; + h[i] = ' '; + h[i + N] = 'x'; + } + + n[N] = '\0'; + h[N * 2] = '\0'; + + /* Ensure we don't match at the first 'x'. */ + h[0] = 'x'; + + char *exp_result = stupid_strstr (h, n); + FOR_EACH_IMPL (impl, 0) + check_result (impl, h, n, exp_result); +} + static int test_main (void) { @@ -158,6 +184,7 @@ test_main (void) check1 (); check2 (); + pr23637 (); printf ("%23s", ""); FOR_EACH_IMPL (impl, 0) @@ -202,6 +229,9 @@ test_main (void) do_test (15, 9, hlen, klen, 1); do_test (15, 15, hlen, klen, 0); do_test (15, 15, hlen, klen, 1); + + do_test (15, 15, hlen + klen * 4, klen * 4, 0); + do_test (15, 15, hlen + klen * 4, klen * 4, 1); } do_test (0, 0, page_size - 1, 16, 0); diff --git a/support/Makefile b/support/Makefile index 652d2cdf69..b43fa524a7 100644 --- a/support/Makefile +++ b/support/Makefile @@ -25,6 +25,7 @@ extra-libs-others = $(extra-libs) extra-libs-noinstall := $(extra-libs) libsupport-routines = \ + blob_repeat \ check \ check_addrinfo \ check_dns_packet \ @@ -43,6 +44,7 @@ libsupport-routines = \ support_capture_subprocess \ support_capture_subprocess_check \ support_chroot \ + support_descriptors \ support_enter_mount_namespace \ support_enter_network_namespace \ support_format_address_family \ @@ -54,6 +56,7 @@ libsupport-routines = \ support_isolate_in_subprocess \ support_openpty \ support_quote_blob \ + support_quote_string \ support_record_failure \ support_run_diff \ support_shared_allocate \ @@ -120,6 +123,7 @@ libsupport-routines = \ xpthread_mutexattr_settype \ xpthread_once \ xpthread_rwlock_init \ + xpthread_rwlock_destroy \ xpthread_rwlock_rdlock \ xpthread_rwlock_unlock \ xpthread_rwlock_wrlock \ @@ -154,9 +158,12 @@ endif tests = \ README-testing \ tst-support-namespace \ + tst-support_blob_repeat \ tst-support_capture_subprocess \ + tst-support_descriptors \ tst-support_format_dns_packet \ tst-support_quote_blob \ + tst-support_quote_string \ tst-support_record_failure \ tst-test_compare \ tst-test_compare_blob \ diff --git a/support/blob_repeat.c b/support/blob_repeat.c new file mode 100644 index 0000000000..718846d81d --- /dev/null +++ b/support/blob_repeat.c @@ -0,0 +1,302 @@ +/* Repeating a memory blob, with alias mapping optimization. + 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 +#include +#include +#include + +/* Small allocations should use malloc directly instead of the mmap + optimization because mappings carry a lot of overhead. */ +static const size_t maximum_small_size = 4 * 1024 * 1024; + +/* Set *RESULT to LEFT * RIGHT. Return true if the multiplication + overflowed. See . */ +static inline bool +check_mul_overflow_size_t (size_t left, size_t right, size_t *result) +{ +#if __GNUC__ >= 5 + return __builtin_mul_overflow (left, right, result); +#else + /* size_t is unsigned so the behavior on overflow is defined. */ + *result = left * right; + size_t half_size_t = ((size_t) 1) << (8 * sizeof (size_t) / 2); + if (__glibc_unlikely ((left | right) >= half_size_t)) + { + if (__glibc_unlikely (right != 0 && *result / right != left)) + return true; + } + return false; +#endif +} + +/* Internal helper for fill. */ +static void +fill0 (char *target, const char *element, size_t element_size, + size_t count) +{ + while (count > 0) + { + memcpy (target, element, element_size); + target += element_size; + --count; + } +} + +/* Fill the buffer at TARGET with COUNT copies of the ELEMENT_SIZE + bytes starting at ELEMENT. */ +static void +fill (char *target, const char *element, size_t element_size, + size_t count) +{ + if (element_size == 0 || count == 0) + return; + else if (element_size == 1) + memset (target, element[0], count); + else if (element_size == sizeof (wchar_t)) + { + wchar_t wc; + memcpy (&wc, element, sizeof (wc)); + wmemset ((wchar_t *) target, wc, count); + } + else if (element_size < 1024 && count > 4096) + { + /* Use larger copies for really small element sizes. */ + char buffer[8192]; + size_t buffer_count = sizeof (buffer) / element_size; + fill0 (buffer, element, element_size, buffer_count); + while (count > 0) + { + size_t copy_count = buffer_count; + if (copy_count > count) + copy_count = count; + size_t copy_bytes = copy_count * element_size; + memcpy (target, buffer, copy_bytes); + target += copy_bytes; + count -= copy_count; + } + } + else + fill0 (target, element, element_size, count); +} + +/* Use malloc instead of mmap for small allocations and unusual size + combinations. */ +static struct support_blob_repeat +allocate_malloc (size_t total_size, const void *element, size_t element_size, + size_t count) +{ + void *buffer = malloc (total_size); + if (buffer == NULL) + return (struct support_blob_repeat) { 0 }; + fill (buffer, element, element_size, count); + return (struct support_blob_repeat) + { + .start = buffer, + .size = total_size, + .use_malloc = true + }; +} + +/* Return the least common multiple of PAGE_SIZE and ELEMENT_SIZE, + avoiding overflow. This assumes that PAGE_SIZE is a power of + two. */ +static size_t +minimum_stride_size (size_t page_size, size_t element_size) +{ + TEST_VERIFY_EXIT (page_size > 0); + TEST_VERIFY_EXIT (element_size > 0); + + /* Compute the number of trailing zeros common to both sizes. */ + unsigned int common_zeros = __builtin_ctzll (page_size | element_size); + + /* In the product, this power of two appears twice, but in the least + common multiple, it appears only once. Therefore, shift one + factor. */ + size_t multiple; + if (check_mul_overflow_size_t (page_size >> common_zeros, element_size, + &multiple)) + return 0; + return multiple; +} + +/* Allocations larger than maximum_small_size potentially use mmap + with alias mappings. */ +static struct support_blob_repeat +allocate_big (size_t total_size, const void *element, size_t element_size, + size_t count) +{ + unsigned long page_size = xsysconf (_SC_PAGESIZE); + size_t stride_size = minimum_stride_size (page_size, element_size); + if (stride_size == 0) + { + errno = EOVERFLOW; + return (struct support_blob_repeat) { 0 }; + } + + /* Ensure that the stride size is at least maximum_small_size. This + is necessary to reduce the number of distinct mappings. */ + if (stride_size < maximum_small_size) + stride_size + = ((maximum_small_size + stride_size - 1) / stride_size) * stride_size; + + if (stride_size > total_size) + /* The mmap optimization would not save anything. */ + return allocate_malloc (total_size, element, element_size, count); + + /* Reserve the memory region. If we cannot create the mapping, + there is no reason to set up the backing file. */ + void *target = mmap (NULL, total_size, PROT_NONE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (target == MAP_FAILED) + return (struct support_blob_repeat) { 0 }; + + /* Create the backing file for the repeated mapping. Call mkstemp + directly to remove the resources backing the temporary file + immediately, once support_blob_repeat_free is called. Using + create_temp_file would result in a warning during post-test + cleanup. */ + int fd; + { + char *temppath = xasprintf ("%s/support_blob_repeat-XXXXXX", test_dir); + fd = mkstemp (temppath); + if (fd < 0) + FAIL_EXIT1 ("mkstemp (\"%s\"): %m", temppath); + xunlink (temppath); + free (temppath); + } + + /* Make sure that there is backing storage, so that the fill + operation will not fault. */ + if (posix_fallocate (fd, 0, stride_size) != 0) + FAIL_EXIT1 ("posix_fallocate (%zu): %m", stride_size); + + /* The stride size must still be a multiple of the page size and + element size. */ + TEST_VERIFY_EXIT ((stride_size % page_size) == 0); + TEST_VERIFY_EXIT ((stride_size % element_size) == 0); + + /* Fill the backing store. */ + { + void *ptr = mmap (target, stride_size, PROT_READ | PROT_WRITE, + MAP_FIXED | MAP_FILE | MAP_SHARED, fd, 0); + if (ptr == MAP_FAILED) + { + int saved_errno = errno; + xmunmap (target, total_size); + xclose (fd); + errno = saved_errno; + return (struct support_blob_repeat) { 0 }; + } + if (ptr != target) + FAIL_EXIT1 ("mapping of %zu bytes moved from %p to %p", + stride_size, target, ptr); + + /* Write the repeating data. */ + fill (target, element, element_size, stride_size / element_size); + + /* Return to a PROT_NONE mapping, just to be on the safe side. */ + ptr = mmap (target, stride_size, PROT_NONE, + MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (ptr == MAP_FAILED) + FAIL_EXIT1 ("Failed to reinstate PROT_NONE mapping: %m"); + if (ptr != target) + FAIL_EXIT1 ("PROT_NONE mapping of %zu bytes moved from %p to %p", + stride_size, target, ptr); + } + + /* Create the alias mappings. */ + { + size_t remaining_size = total_size; + char *current = target; + int flags = MAP_FIXED | MAP_FILE | MAP_PRIVATE; +#ifdef MAP_NORESERVE + flags |= MAP_NORESERVE; +#endif + while (remaining_size > 0) + { + size_t to_map = stride_size; + if (to_map > remaining_size) + to_map = remaining_size; + void *ptr = mmap (current, to_map, PROT_READ | PROT_WRITE, + flags, fd, 0); + if (ptr == MAP_FAILED) + { + int saved_errno = errno; + xmunmap (target, total_size); + xclose (fd); + errno = saved_errno; + return (struct support_blob_repeat) { 0 }; + } + if (ptr != current) + FAIL_EXIT1 ("MAP_PRIVATE mapping of %zu bytes moved from %p to %p", + to_map, target, ptr); + remaining_size -= to_map; + current += to_map; + } + } + + xclose (fd); + + return (struct support_blob_repeat) + { + .start = target, + .size = total_size, + .use_malloc = false + }; +} + +struct support_blob_repeat +support_blob_repeat_allocate (const void *element, size_t element_size, + size_t count) +{ + size_t total_size; + if (check_mul_overflow_size_t (element_size, count, &total_size)) + { + errno = EOVERFLOW; + return (struct support_blob_repeat) { 0 }; + } + if (total_size <= maximum_small_size) + return allocate_malloc (total_size, element, element_size, count); + else + return allocate_big (total_size, element, element_size, count); +} + +void +support_blob_repeat_free (struct support_blob_repeat *blob) +{ + if (blob->size > 0) + { + int saved_errno = errno; + if (blob->use_malloc) + free (blob->start); + else + xmunmap (blob->start, blob->size); + errno = saved_errno; + } + *blob = (struct support_blob_repeat) { 0 }; +} diff --git a/support/blob_repeat.h b/support/blob_repeat.h new file mode 100644 index 0000000000..8e9d7ff5f1 --- /dev/null +++ b/support/blob_repeat.h @@ -0,0 +1,44 @@ +/* Repeating a memory blob, with alias mapping optimization. + 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 + . */ + +#ifndef SUPPORT_BLOB_REPEAT_H +#define SUPPORT_BLOB_REPEAT_H + +#include +#include + +struct support_blob_repeat +{ + void *start; + size_t size; + bool use_malloc; +}; + +/* Return an allocation of COUNT elements, each of ELEMENT_SIZE bytes, + initialized with the bytes starting at ELEMENT. The memory is + writable (and thus counts towards the commit charge). In case of + on error, all members of the return struct are zero-initialized, + and errno is set accordingly. */ +struct support_blob_repeat support_blob_repeat_allocate (const void *element, + size_t element_size, + size_t count); + +/* Deallocate the blob created by support_blob_repeat_allocate. */ +void support_blob_repeat_free (struct support_blob_repeat *); + +#endif /* SUPPORT_BLOB_REPEAT_H */ diff --git a/support/check.h b/support/check.h index b3a4645e92..10468b74d8 100644 --- a/support/check.h +++ b/support/check.h @@ -170,6 +170,10 @@ int support_report_failure (int status) /* Internal function used to test the failure recording framework. */ void support_record_failure_reset (void); +/* Returns true or false depending on whether there have been test + failures or not. */ +int support_record_failure_is_failed (void); + __END_DECLS #endif /* SUPPORT_CHECK_H */ diff --git a/support/descriptors.h b/support/descriptors.h new file mode 100644 index 0000000000..8ec4cbbdfb --- /dev/null +++ b/support/descriptors.h @@ -0,0 +1,47 @@ +/* Monitoring file descriptor usage. + 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 + . */ + +#ifndef SUPPORT_DESCRIPTORS_H +#define SUPPORT_DESCRIPTORS_H + +#include + +/* Opaque pointer, for capturing file descriptor lists. */ +struct support_descriptors; + +/* Record the currently open file descriptors and store them in the + returned list. Terminate the process if the listing operation + fails. */ +struct support_descriptors *support_descriptors_list (void); + +/* Deallocate the list of descriptors. */ +void support_descriptors_free (struct support_descriptors *); + +/* Write the list of descriptors to STREAM, adding PREFIX to each + line. */ +void support_descriptors_dump (struct support_descriptors *, + const char *prefix, FILE *stream); + +/* Check for file descriptor leaks and other file descriptor changes: + Compare the current list of descriptors with the passed list. + Record a test failure if there are additional open descriptors, + descriptors have been closed, or if a change in file descriptor can + be detected. */ +void support_descriptors_check (struct support_descriptors *); + +#endif /* SUPPORT_DESCRIPTORS_H */ diff --git a/support/support.h b/support/support.h index b61fe0735c..4ea92e1c21 100644 --- a/support/support.h +++ b/support/support.h @@ -65,6 +65,11 @@ void support_write_file_string (const char *path, const char *contents); the result). */ char *support_quote_blob (const void *blob, size_t length); +/* Quote the contents of the string, in such a way that the result + string can be included in a C literal (in single/double quotes, + without putting the quotes into the result). */ +char *support_quote_string (const char *); + /* Error-checking wrapper functions which terminate the process on error. */ diff --git a/support/support_capture_subprocess.c b/support/support_capture_subprocess.c index 6d2029e13b..93f6ea3102 100644 --- a/support/support_capture_subprocess.c +++ b/support/support_capture_subprocess.c @@ -59,8 +59,12 @@ support_capture_subprocess (void (*callback) (void *), void *closure) int stdout_pipe[2]; xpipe (stdout_pipe); + TEST_VERIFY (stdout_pipe[0] > STDERR_FILENO); + TEST_VERIFY (stdout_pipe[1] > STDERR_FILENO); int stderr_pipe[2]; xpipe (stderr_pipe); + TEST_VERIFY (stderr_pipe[0] > STDERR_FILENO); + TEST_VERIFY (stderr_pipe[1] > STDERR_FILENO); TEST_VERIFY (fflush (stdout) == 0); TEST_VERIFY (fflush (stderr) == 0); @@ -72,6 +76,8 @@ support_capture_subprocess (void (*callback) (void *), void *closure) xclose (stderr_pipe[0]); xdup2 (stdout_pipe[1], STDOUT_FILENO); xdup2 (stderr_pipe[1], STDERR_FILENO); + xclose (stdout_pipe[1]); + xclose (stderr_pipe[1]); callback (closure); _exit (0); } diff --git a/support/support_descriptors.c b/support/support_descriptors.c new file mode 100644 index 0000000000..d66cf55080 --- /dev/null +++ b/support/support_descriptors.c @@ -0,0 +1,274 @@ +/* Monitoring file descriptor usage. + 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 + +struct procfs_descriptor +{ + int fd; + char *link_target; + dev_t dev; + ino64_t ino; +}; + +/* Used with qsort. */ +static int +descriptor_compare (const void *l, const void *r) +{ + const struct procfs_descriptor *left = l; + const struct procfs_descriptor *right = r; + /* Cannot overflow due to limited file descriptor range. */ + return left->fd - right->fd; +} + +#define DYNARRAY_STRUCT descriptor_list +#define DYNARRAY_ELEMENT struct procfs_descriptor +#define DYNARRAY_PREFIX descriptor_list_ +#define DYNARRAY_ELEMENT_FREE(e) free ((e)->link_target) +#define DYNARRAY_INITIAL_SIZE 0 +#include + +struct support_descriptors +{ + struct descriptor_list list; +}; + +struct support_descriptors * +support_descriptors_list (void) +{ + struct support_descriptors *result = xmalloc (sizeof (*result)); + descriptor_list_init (&result->list); + + DIR *fds = opendir ("/proc/self/fd"); + if (fds == NULL) + FAIL_EXIT1 ("opendir (\"/proc/self/fd\"): %m"); + + while (true) + { + errno = 0; + struct dirent64 *e = readdir64 (fds); + if (e == NULL) + { + if (errno != 0) + FAIL_EXIT1 ("readdir: %m"); + break; + } + + if (e->d_name[0] == '.') + continue; + + char *endptr; + long int fd = strtol (e->d_name, &endptr, 10); + if (*endptr != '\0' || fd < 0 || fd > INT_MAX) + FAIL_EXIT1 ("readdir: invalid file descriptor name: /proc/self/fd/%s", + e->d_name); + + /* Skip the descriptor which is used to enumerate the + descriptors. */ + if (fd == dirfd (fds)) + continue; + + char *target; + { + char *path = xasprintf ("/proc/self/fd/%ld", fd); + target = xreadlink (path); + free (path); + } + struct stat64 st; + if (fstat64 (fd, &st) != 0) + FAIL_EXIT1 ("readdir: fstat64 (%ld) failed: %m", fd); + + struct procfs_descriptor *item = descriptor_list_emplace (&result->list); + if (item == NULL) + FAIL_EXIT1 ("descriptor_list_emplace: %m"); + item->fd = fd; + item->link_target = target; + item->dev = st.st_dev; + item->ino = st.st_ino; + } + + closedir (fds); + + /* Perform a merge join between descrs and current. This assumes + that the arrays are sorted by file descriptor. */ + + qsort (descriptor_list_begin (&result->list), + descriptor_list_size (&result->list), + sizeof (struct procfs_descriptor), descriptor_compare); + + return result; +} + +void +support_descriptors_free (struct support_descriptors *descrs) +{ + descriptor_list_free (&descrs->list); + free (descrs); +} + +void +support_descriptors_dump (struct support_descriptors *descrs, + const char *prefix, FILE *fp) +{ + struct procfs_descriptor *end = descriptor_list_end (&descrs->list); + for (struct procfs_descriptor *d = descriptor_list_begin (&descrs->list); + d != end; ++d) + { + char *quoted = support_quote_string (d->link_target); + fprintf (fp, "%s%d: target=\"%s\" major=%lld minor=%lld ino=%lld\n", + prefix, d->fd, quoted, + (long long int) major (d->dev), + (long long int) minor (d->dev), + (long long int) d->ino); + free (quoted); + } +} + +static void +dump_mismatch (bool *first, + struct support_descriptors *descrs, + struct support_descriptors *current) +{ + if (*first) + *first = false; + else + return; + + puts ("error: Differences found in descriptor set"); + puts ("Reference descriptor set:"); + support_descriptors_dump (descrs, " ", stdout); + puts ("Current descriptor set:"); + support_descriptors_dump (current, " ", stdout); + puts ("Differences:"); +} + +static void +report_closed_descriptor (bool *first, + struct support_descriptors *descrs, + struct support_descriptors *current, + struct procfs_descriptor *left) +{ + support_record_failure (); + dump_mismatch (first, descrs, current); + printf ("error: descriptor %d was closed\n", left->fd); +} + +static void +report_opened_descriptor (bool *first, + struct support_descriptors *descrs, + struct support_descriptors *current, + struct procfs_descriptor *right) +{ + support_record_failure (); + dump_mismatch (first, descrs, current); + char *quoted = support_quote_string (right->link_target); + printf ("error: descriptor %d was opened (\"%s\")\n", right->fd, quoted); + free (quoted); +} + +void +support_descriptors_check (struct support_descriptors *descrs) +{ + struct support_descriptors *current = support_descriptors_list (); + + /* Perform a merge join between descrs and current. This assumes + that the arrays are sorted by file descriptor. */ + + struct procfs_descriptor *left = descriptor_list_begin (&descrs->list); + struct procfs_descriptor *left_end = descriptor_list_end (&descrs->list); + struct procfs_descriptor *right = descriptor_list_begin (¤t->list); + struct procfs_descriptor *right_end = descriptor_list_end (¤t->list); + + bool first = true; + while (left != left_end && right != right_end) + { + if (left->fd == right->fd) + { + if (strcmp (left->link_target, right->link_target) != 0) + { + support_record_failure (); + char *left_quoted = support_quote_string (left->link_target); + char *right_quoted = support_quote_string (right->link_target); + dump_mismatch (&first, descrs, current); + printf ("error: descriptor %d changed from \"%s\" to \"%s\"\n", + left->fd, left_quoted, right_quoted); + free (left_quoted); + free (right_quoted); + } + if (left->dev != right->dev) + { + support_record_failure (); + dump_mismatch (&first, descrs, current); + printf ("error: descriptor %d changed device" + " from %lld:%lld to %lld:%lld\n", + left->fd, + (long long int) major (left->dev), + (long long int) minor (left->dev), + (long long int) major (right->dev), + (long long int) minor (right->dev)); + } + if (left->ino != right->ino) + { + support_record_failure (); + dump_mismatch (&first, descrs, current); + printf ("error: descriptor %d changed ino from %lld to %lld\n", + left->fd, + (long long int) left->ino, (long long int) right->ino); + } + ++left; + ++right; + } + else if (left->fd < right->fd) + { + /* Gap on the right. */ + report_closed_descriptor (&first, descrs, current, left); + ++left; + } + else + { + /* Gap on the left. */ + TEST_VERIFY_EXIT (left->fd > right->fd); + report_opened_descriptor (&first, descrs, current, right); + ++right; + } + } + + while (left != left_end) + { + /* Closed descriptors (more descriptors on the left). */ + report_closed_descriptor (&first, descrs, current, left); + ++left; + } + + while (right != right_end) + { + /* Opened descriptors (more descriptors on the right). */ + report_opened_descriptor (&first, descrs, current, right); + ++right; + } + + support_descriptors_free (current); +} diff --git a/support/support_quote_string.c b/support/support_quote_string.c new file mode 100644 index 0000000000..d324371b13 --- /dev/null +++ b/support/support_quote_string.c @@ -0,0 +1,26 @@ +/* Quote a string so that it can be used in C literals. + 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 + +char * +support_quote_string (const char *str) +{ + return support_quote_blob (str, strlen (str)); +} diff --git a/support/support_record_failure.c b/support/support_record_failure.c index 356798f556..17ab1d80ef 100644 --- a/support/support_record_failure.c +++ b/support/support_record_failure.c @@ -104,3 +104,11 @@ support_record_failure_reset (void) __atomic_store_n (&state->failed, 0, __ATOMIC_RELAXED); __atomic_add_fetch (&state->counter, 0, __ATOMIC_RELAXED); } + +int +support_record_failure_is_failed (void) +{ + /* Relaxed MO is sufficient because we need (blocking) external + synchronization for reliable test error reporting anyway. */ + return __atomic_load_n (&state->failed, __ATOMIC_RELAXED); +} diff --git a/support/support_test_main.c b/support/support_test_main.c index 23429779ac..fa3c2e06de 100644 --- a/support/support_test_main.c +++ b/support/support_test_main.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -86,6 +87,19 @@ static pid_t test_pid; /* The cleanup handler passed to test_main. */ static void (*cleanup_function) (void); +static void +print_timestamp (const char *what, struct timeval tv) +{ + struct tm tm; + if (gmtime_r (&tv.tv_sec, &tm) == NULL) + printf ("%s: %lld.%06d\n", + what, (long long int) tv.tv_sec, (int) tv.tv_usec); + else + printf ("%s: %04d-%02d-%02dT%02d:%02d:%02d.%06d\n", + what, 1900 + tm.tm_year, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec, (int) tv.tv_usec); +} + /* Timeout handler. We kill the child and exit with an error. */ static void __attribute__ ((noreturn)) @@ -94,6 +108,13 @@ signal_handler (int sig) int killed; int status; + /* Do this first to avoid further interference from the + subprocess. */ + struct timeval now; + bool now_available = gettimeofday (&now, NULL) == 0; + struct stat64 st; + bool st_available = fstat64 (STDOUT_FILENO, &st) == 0 && st.st_mtime != 0; + assert (test_pid > 1); /* Kill the whole process group. */ kill (-test_pid, SIGKILL); @@ -144,6 +165,13 @@ signal_handler (int sig) printf ("Timed out: killed the child process but it exited %d\n", WEXITSTATUS (status)); + if (now_available) + print_timestamp ("Termination time", now); + if (st_available) + print_timestamp ("Last write to standard output", + (struct timeval) { st.st_mtim.tv_sec, + st.st_mtim.tv_nsec / 1000 }); + /* Exit with an error. */ exit (1); } diff --git a/support/tst-support_blob_repeat.c b/support/tst-support_blob_repeat.c new file mode 100644 index 0000000000..1978c14488 --- /dev/null +++ b/support/tst-support_blob_repeat.c @@ -0,0 +1,85 @@ +/* Tests for + 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 + +static int +do_test (void) +{ + struct support_blob_repeat repeat + = support_blob_repeat_allocate ("5", 1, 5); + TEST_COMPARE_BLOB (repeat.start, repeat.size, "55555", 5); + support_blob_repeat_free (&repeat); + + repeat = support_blob_repeat_allocate ("ABC", 3, 3); + TEST_COMPARE_BLOB (repeat.start, repeat.size, "ABCABCABC", 9); + support_blob_repeat_free (&repeat); + + repeat = support_blob_repeat_allocate ("abc", 4, 3); + TEST_COMPARE_BLOB (repeat.start, repeat.size, "abc\0abc\0abc", 12); + support_blob_repeat_free (&repeat); + + size_t gigabyte = 1U << 30; + repeat = support_blob_repeat_allocate ("X", 1, gigabyte + 1); + if (repeat.start == NULL) + puts ("warning: not enough memory for 1 GiB mapping"); + else + { + TEST_COMPARE (repeat.size, gigabyte + 1); + { + unsigned char *p = repeat.start; + for (size_t i = 0; i < gigabyte + 1; ++i) + if (p[i] != 'X') + FAIL_EXIT1 ("invalid byte 0x%02x at %zu", p[i], i); + + /* Check that there is no sharing across the mapping. */ + p[0] = 'Y'; + p[1U << 24] = 'Z'; + for (size_t i = 0; i < gigabyte + 1; ++i) + if (i == 0) + TEST_COMPARE (p[i], 'Y'); + else if (i == 1U << 24) + TEST_COMPARE (p[i], 'Z'); + else if (p[i] != 'X') + FAIL_EXIT1 ("invalid byte 0x%02x at %zu", p[i], i); + } + } + support_blob_repeat_free (&repeat); + + repeat = support_blob_repeat_allocate ("012345678", 9, 10 * 1000 * 1000); + if (repeat.start == NULL) + puts ("warning: not enough memory for large mapping"); + else + { + unsigned char *p = repeat.start; + for (int i = 0; i < 10 * 1000 * 1000; ++i) + for (int j = 0; j <= 8; ++j) + if (p[i * 9 + j] != '0' + j) + { + printf ("error: element %d index %d\n", i, j); + TEST_COMPARE (p[i * 9 + j], '0' + j); + } + } + support_blob_repeat_free (&repeat); + + return 0; +} + +#include diff --git a/support/tst-support_descriptors.c b/support/tst-support_descriptors.c new file mode 100644 index 0000000000..5e9e824bc3 --- /dev/null +++ b/support/tst-support_descriptors.c @@ -0,0 +1,198 @@ +/* Tests for monitoring file descriptor usage. + 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 + +/* This is the next free descriptor that the subprocess will pick. */ +static int free_descriptor; + +static void +subprocess_no_change (void *closure) +{ + struct support_descriptors *descrs = support_descriptors_list (); + int fd = xopen ("/dev/null", O_WRONLY, 0); + TEST_COMPARE (fd, free_descriptor); + xclose (fd); + support_descriptors_free (descrs); +} + +static void +subprocess_closed_descriptor (void *closure) +{ + int fd = xopen ("/dev/null", O_WRONLY, 0); + TEST_COMPARE (fd, free_descriptor); + struct support_descriptors *descrs = support_descriptors_list (); + xclose (fd); + support_descriptors_check (descrs); /* Will report failure. */ + puts ("EOT"); + support_descriptors_free (descrs); +} + +static void +subprocess_opened_descriptor (void *closure) +{ + struct support_descriptors *descrs = support_descriptors_list (); + int fd = xopen ("/dev/null", O_WRONLY, 0); + TEST_COMPARE (fd, free_descriptor); + support_descriptors_check (descrs); /* Will report failure. */ + puts ("EOT"); + support_descriptors_free (descrs); +} + +static void +subprocess_changed_descriptor (void *closure) +{ + int fd = xopen ("/dev/null", O_WRONLY, 0); + TEST_COMPARE (fd, free_descriptor); + struct support_descriptors *descrs = support_descriptors_list (); + xclose (fd); + TEST_COMPARE (xopen ("/dev", O_DIRECTORY | O_RDONLY, 0), fd); + support_descriptors_check (descrs); /* Will report failure. */ + puts ("EOT"); + support_descriptors_free (descrs); +} + +static void +report_subprocess_output (const char *name, + struct support_capture_subprocess *proc) +{ + printf ("info: BEGIN %s output\n" + "%s" + "info: END %s output\n", + name, proc->out.buffer, name); +} + +/* Use an explicit flag to preserve failure status across + support_record_failure_reset calls. */ +static bool good = true; + +static void +test_run (void) +{ + struct support_capture_subprocess proc = support_capture_subprocess + (&subprocess_no_change, NULL); + support_capture_subprocess_check (&proc, "subprocess_no_change", + 0, sc_allow_none); + support_capture_subprocess_free (&proc); + + char *expected = xasprintf ("\nDifferences:\n" + "error: descriptor %d was closed\n" + "EOT\n", + free_descriptor); + good = good && !support_record_failure_is_failed (); + proc = support_capture_subprocess (&subprocess_closed_descriptor, NULL); + good = good && support_record_failure_is_failed (); + support_record_failure_reset (); /* Discard the reported error. */ + report_subprocess_output ("subprocess_closed_descriptor", &proc); + TEST_VERIFY (strstr (proc.out.buffer, expected) != NULL); + support_capture_subprocess_check (&proc, "subprocess_closed_descriptor", + 0, sc_allow_stdout); + support_capture_subprocess_free (&proc); + free (expected); + + expected = xasprintf ("\nDifferences:\n" + "error: descriptor %d was opened (\"/dev/null\")\n" + "EOT\n", + free_descriptor); + good = good && !support_record_failure_is_failed (); + proc = support_capture_subprocess (&subprocess_opened_descriptor, NULL); + good = good && support_record_failure_is_failed (); + support_record_failure_reset (); /* Discard the reported error. */ + report_subprocess_output ("subprocess_opened_descriptor", &proc); + TEST_VERIFY (strstr (proc.out.buffer, expected) != NULL); + support_capture_subprocess_check (&proc, "subprocess_opened_descriptor", + 0, sc_allow_stdout); + support_capture_subprocess_free (&proc); + free (expected); + + expected = xasprintf ("\nDifferences:\n" + "error: descriptor %d changed from \"/dev/null\"" + " to \"/dev\"\n" + "error: descriptor %d changed ino ", + free_descriptor, free_descriptor); + good = good && !support_record_failure_is_failed (); + proc = support_capture_subprocess (&subprocess_changed_descriptor, NULL); + good = good && support_record_failure_is_failed (); + support_record_failure_reset (); /* Discard the reported error. */ + report_subprocess_output ("subprocess_changed_descriptor", &proc); + TEST_VERIFY (strstr (proc.out.buffer, expected) != NULL); + support_capture_subprocess_check (&proc, "subprocess_changed_descriptor", + 0, sc_allow_stdout); + support_capture_subprocess_free (&proc); + free (expected); +} + +static int +do_test (void) +{ + puts ("info: initial descriptor set"); + { + struct support_descriptors *descrs = support_descriptors_list (); + support_descriptors_dump (descrs, "info: ", stdout); + support_descriptors_free (descrs); + } + + free_descriptor = xopen ("/dev/null", O_WRONLY, 0); + puts ("info: descriptor set with additional free descriptor"); + { + struct support_descriptors *descrs = support_descriptors_list (); + support_descriptors_dump (descrs, "info: ", stdout); + support_descriptors_free (descrs); + } + TEST_VERIFY (free_descriptor >= 3); + xclose (free_descriptor); + + /* Initial test run without a sentinel descriptor. The presence of + such a descriptor exercises different conditions in the list + comparison in support_descriptors_check. */ + test_run (); + + /* Allocate a sentinel descriptor at the end of the descriptor list, + after free_descriptor. */ + int sentinel_fd; + { + int fd = xopen ("/dev/full", O_WRONLY, 0); + TEST_COMPARE (fd, free_descriptor); + sentinel_fd = dup (fd); + TEST_VERIFY_EXIT (sentinel_fd > fd); + xclose (fd); + } + puts ("info: descriptor set with sentinel descriptor"); + { + struct support_descriptors *descrs = support_descriptors_list (); + support_descriptors_dump (descrs, "info: ", stdout); + support_descriptors_free (descrs); + } + + /* Second test run with sentinel descriptor. */ + test_run (); + + xclose (sentinel_fd); + + return !good; +} + +#include diff --git a/support/tst-support_quote_string.c b/support/tst-support_quote_string.c new file mode 100644 index 0000000000..3c004759b7 --- /dev/null +++ b/support/tst-support_quote_string.c @@ -0,0 +1,60 @@ +/* Test the support_quote_string function. + 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 + +static int +do_test (void) +{ + char *p = support_quote_string (""); + TEST_COMPARE (strlen (p), 0); + free (p); + p = support_quote_string ("X"); + TEST_COMPARE (strlen (p), 1); + TEST_COMPARE (p[0], 'X'); + free (p); + + /* Check escaping of backslash-escaped characters, and lack of + escaping for other shell meta-characters. */ + p = support_quote_string ("$()*?`@[]{}~\'\"X"); + TEST_COMPARE (strcmp (p, "$()*?`@[]{}~\\'\\\"X"), 0); + free (p); + + /* Check lack of escaping for letters and digits. */ +#define LETTERS_AND_DIGTS \ + "abcdefghijklmnopqrstuvwxyz" \ + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \ + "0123456789" + p = support_quote_string (LETTERS_AND_DIGTS "@"); + TEST_COMPARE (strcmp (p, LETTERS_AND_DIGTS "@"), 0); + free (p); + + /* Check escaping of control characters and other non-printable + characters. */ + p = support_quote_string ("\r\n\t\a\b\f\v\1\177\200\377@"); + TEST_COMPARE (strcmp (p, "\\r\\n\\t\\a\\b\\f\\v\\001" + "\\177\\200\\377@"), 0); + free (p); + + return 0; +} + +#include diff --git a/support/xpthread_rwlock_destroy.c b/support/xpthread_rwlock_destroy.c new file mode 100644 index 0000000000..6d6e953569 --- /dev/null +++ b/support/xpthread_rwlock_destroy.c @@ -0,0 +1,26 @@ +/* pthread_rwlock_destroy with error checking. + Copyright (C) 2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +void +xpthread_rwlock_destroy (pthread_rwlock_t *rwlock) +{ + xpthread_check_return ("pthread_rwlock_destroy", + pthread_rwlock_destroy (rwlock)); +} diff --git a/support/xthread.h b/support/xthread.h index 623f5ad0ac..1af7728087 100644 --- a/support/xthread.h +++ b/support/xthread.h @@ -84,6 +84,7 @@ void xpthread_rwlockattr_setkind_np (pthread_rwlockattr_t *attr, int pref); void xpthread_rwlock_wrlock (pthread_rwlock_t *rwlock); void xpthread_rwlock_rdlock (pthread_rwlock_t *rwlock); void xpthread_rwlock_unlock (pthread_rwlock_t *rwlock); +void xpthread_rwlock_destroy (pthread_rwlock_t *rwlock); __END_DECLS diff --git a/sysdeps/aarch64/dl-irel.h b/sysdeps/aarch64/dl-irel.h index 5889ee187b..bef71ed0f3 100644 --- a/sysdeps/aarch64/dl-irel.h +++ b/sysdeps/aarch64/dl-irel.h @@ -47,7 +47,7 @@ elf_irela (const ElfW(Rela) *reloc) *reloc_addr = value; } else - __libc_fatal ("unexpected reloc type in static binary"); + __libc_fatal ("Unexpected reloc type in static binary.\n"); } #endif diff --git a/sysdeps/alpha/fpu/libm-test-ulps b/sysdeps/alpha/fpu/libm-test-ulps index 12a6127ddf..3fc18d57d7 100644 --- a/sysdeps/alpha/fpu/libm-test-ulps +++ b/sysdeps/alpha/fpu/libm-test-ulps @@ -1006,7 +1006,9 @@ ildouble: 2 ldouble: 2 Function: "cos": +double: 1 float: 1 +idouble: 1 ifloat: 1 ildouble: 1 ldouble: 1 @@ -1932,7 +1934,9 @@ ildouble: 1 ldouble: 1 Function: "pow": +double: 1 float: 1 +idouble: 1 ifloat: 1 ildouble: 2 ldouble: 2 @@ -1962,7 +1966,9 @@ ildouble: 2 ldouble: 2 Function: "sin": +double: 1 float: 1 +idouble: 1 ifloat: 1 ildouble: 1 ldouble: 1 @@ -1992,7 +1998,9 @@ ildouble: 3 ldouble: 3 Function: "sincos": +double: 1 float: 1 +idouble: 1 ifloat: 1 ildouble: 1 ldouble: 1 diff --git a/sysdeps/arm/dl-irel.h b/sysdeps/arm/dl-irel.h index a7b6456075..be6eb7743e 100644 --- a/sysdeps/arm/dl-irel.h +++ b/sysdeps/arm/dl-irel.h @@ -46,7 +46,7 @@ elf_irel (const Elf32_Rel *reloc) *reloc_addr = value; } else - __libc_fatal ("unexpected reloc type in static binary"); + __libc_fatal ("Unexpected reloc type in static binary.\n"); } #endif /* dl-irel.h */ diff --git a/sysdeps/generic/unwind-dw2.c b/sysdeps/generic/unwind-dw2.c index 082609b34a..724c16a7f0 100644 --- a/sysdeps/generic/unwind-dw2.c +++ b/sysdeps/generic/unwind-dw2.c @@ -843,7 +843,7 @@ execute_cfa_program (const unsigned char *insn_ptr, struct frame_state_reg_info *old_rs = fs->regs.prev; #ifdef _LIBC if (old_rs == NULL) - __libc_fatal ("invalid DWARF unwind data"); + __libc_fatal ("Invalid DWARF unwind data.\n"); else #endif { diff --git a/sysdeps/htl/pt-getspecific.c b/sysdeps/htl/pt-getspecific.c index a0227a67f6..64ddf9551a 100644 --- a/sysdeps/htl/pt-getspecific.c +++ b/sysdeps/htl/pt-getspecific.c @@ -36,3 +36,4 @@ __pthread_getspecific (pthread_key_t key) return self->thread_specifics[key]; } strong_alias (__pthread_getspecific, pthread_getspecific); +hidden_def (__pthread_getspecific) diff --git a/sysdeps/htl/pt-setspecific.c b/sysdeps/htl/pt-setspecific.c index a46a12f157..02aff417ef 100644 --- a/sysdeps/htl/pt-setspecific.c +++ b/sysdeps/htl/pt-setspecific.c @@ -48,3 +48,4 @@ __pthread_setspecific (pthread_key_t key, const void *value) return 0; } strong_alias (__pthread_setspecific, pthread_setspecific); +hidden_def (__pthread_setspecific) diff --git a/sysdeps/htl/pthreadP.h b/sysdeps/htl/pthreadP.h index 132ac1718e..71c2fcd9c6 100644 --- a/sysdeps/htl/pthreadP.h +++ b/sysdeps/htl/pthreadP.h @@ -68,6 +68,8 @@ struct __pthread_cancelation_handler **___pthread_get_cleanup_stack (void) attri #if IS_IN (libpthread) hidden_proto (__pthread_key_create) +hidden_proto (__pthread_getspecific) +hidden_proto (__pthread_setspecific) hidden_proto (_pthread_mutex_init) #endif diff --git a/sysdeps/i386/dl-cet.c b/sysdeps/i386/dl-cet.c deleted file mode 100644 index 5d9a4e8d51..0000000000 --- a/sysdeps/i386/dl-cet.c +++ /dev/null @@ -1,67 +0,0 @@ -/* Linux/i386 CET initializers function. - Copyright (C) 2018 Free Software Foundation, Inc. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - . */ - - -#define LINKAGE static inline -#define _dl_cet_check cet_check -#include -#undef _dl_cet_check - -#ifdef SHARED -void -_dl_cet_check (struct link_map *main_map, const char *program) -{ - cet_check (main_map, program); - - if ((GL(dl_x86_feature_1)[0] & GNU_PROPERTY_X86_FEATURE_1_SHSTK)) - { - /* Replace _dl_runtime_resolve and _dl_runtime_profile with - _dl_runtime_resolve_shstk and _dl_runtime_profile_shstk, - respectively if SHSTK is enabled. */ - extern void _dl_runtime_resolve (Elf32_Word) attribute_hidden; - extern void _dl_runtime_resolve_shstk (Elf32_Word) attribute_hidden; - extern void _dl_runtime_profile (Elf32_Word) attribute_hidden; - extern void _dl_runtime_profile_shstk (Elf32_Word) attribute_hidden; - unsigned int i; - struct link_map *l; - Elf32_Addr *got; - - if (main_map->l_info[DT_JMPREL]) - { - got = (Elf32_Addr *) D_PTR (main_map, l_info[DT_PLTGOT]); - if (got[2] == (Elf32_Addr) &_dl_runtime_resolve) - got[2] = (Elf32_Addr) &_dl_runtime_resolve_shstk; - else if (got[2] == (Elf32_Addr) &_dl_runtime_profile) - got[2] = (Elf32_Addr) &_dl_runtime_profile_shstk; - } - - i = main_map->l_searchlist.r_nlist; - while (i-- > 0) - { - l = main_map->l_initfini[i]; - if (l->l_info[DT_JMPREL]) - { - got = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]); - if (got[2] == (Elf32_Addr) &_dl_runtime_resolve) - got[2] = (Elf32_Addr) &_dl_runtime_resolve_shstk; - else if (got[2] == (Elf32_Addr) &_dl_runtime_profile) - got[2] = (Elf32_Addr) &_dl_runtime_profile_shstk; - } - } - } -} -#endif diff --git a/sysdeps/i386/dl-irel.h b/sysdeps/i386/dl-irel.h index 55303180c7..bcaf0668ac 100644 --- a/sysdeps/i386/dl-irel.h +++ b/sysdeps/i386/dl-irel.h @@ -45,7 +45,7 @@ elf_irel (const Elf32_Rel *reloc) *reloc_addr = value; } else - __libc_fatal ("unexpected reloc type in static binary"); + __libc_fatal ("Unexpected reloc type in static binary.\n"); } #endif /* dl-irel.h */ diff --git a/sysdeps/i386/dl-machine.h b/sysdeps/i386/dl-machine.h index 1afdcbd9ea..f6cfb90e21 100644 --- a/sysdeps/i386/dl-machine.h +++ b/sysdeps/i386/dl-machine.h @@ -67,6 +67,11 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) Elf32_Addr *got; extern void _dl_runtime_resolve (Elf32_Word) attribute_hidden; extern void _dl_runtime_profile (Elf32_Word) attribute_hidden; + extern void _dl_runtime_resolve_shstk (Elf32_Word) attribute_hidden; + extern void _dl_runtime_profile_shstk (Elf32_Word) attribute_hidden; + /* Check if SHSTK is enabled by kernel. */ + bool shstk_enabled + = (GL(dl_x86_feature_1)[0] & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0; if (l->l_info[DT_JMPREL] && lazy) { @@ -93,7 +98,9 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) end in this function. */ if (__glibc_unlikely (profile)) { - got[2] = (Elf32_Addr) &_dl_runtime_profile; + got[2] = (shstk_enabled + ? (Elf32_Addr) &_dl_runtime_profile_shstk + : (Elf32_Addr) &_dl_runtime_profile); if (GLRO(dl_profile) != NULL && _dl_name_match_p (GLRO(dl_profile), l)) @@ -104,7 +111,9 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) else /* 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. */ - got[2] = (Elf32_Addr) &_dl_runtime_resolve; + got[2] = (shstk_enabled + ? (Elf32_Addr) &_dl_runtime_resolve_shstk + : (Elf32_Addr) &_dl_runtime_resolve); } return lazy; diff --git a/sysdeps/i386/start.S b/sysdeps/i386/start.S index 91035fa83f..e35e9bd31b 100644 --- a/sysdeps/i386/start.S +++ b/sysdeps/i386/start.S @@ -52,10 +52,11 @@ NULL */ - .text - .globl _start - .type _start,@function -_start: +#include + +ENTRY (_start) + /* Clearing frame pointer is insufficient, use CFI. */ + cfi_undefined (eip) /* Clear the frame pointer. The ABI suggests this be done, to mark the outermost frame obviously. */ xorl %ebp, %ebp @@ -131,6 +132,7 @@ _start: 1: movl (%esp), %ebx ret #endif +END (_start) /* To fulfill the System V/i386 ABI we need this symbol. Yuck, it's so meaningless since we don't support machines < 80386. */ diff --git a/sysdeps/ia64/fpu/e_exp2f.S b/sysdeps/ia64/fpu/e_exp2f.S index 77bc6ea686..3010a95a2d 100644 --- a/sysdeps/ia64/fpu/e_exp2f.S +++ b/sysdeps/ia64/fpu/e_exp2f.S @@ -221,7 +221,7 @@ LOCAL_OBJECT_END(T_table) .section .text -GLOBAL_LIBM_ENTRY(__exp2f) +WEAK_LIBM_ENTRY(exp2f) {.mfi @@ -468,10 +468,10 @@ OUT_RANGE_exp2: } ;; -GLOBAL_LIBM_END(__exp2f) +WEAK_LIBM_END(exp2f) libm_alias_float_other (__exp2, exp2) #ifdef SHARED -.symver __exp2f,exp2f@@GLIBC_2.27 +.symver exp2f,exp2f@@GLIBC_2.27 .weak __exp2f_compat .set __exp2f_compat,__exp2f .symver __exp2f_compat,exp2f@GLIBC_2.2 diff --git a/sysdeps/ia64/fpu/e_log2f.S b/sysdeps/ia64/fpu/e_log2f.S index 5ca3bd61ea..e4ea094344 100644 --- a/sysdeps/ia64/fpu/e_log2f.S +++ b/sysdeps/ia64/fpu/e_log2f.S @@ -252,7 +252,7 @@ LOCAL_OBJECT_END(T_table) .section .text -GLOBAL_LIBM_ENTRY(__log2f) +WEAK_LIBM_ENTRY(log2f) { .mfi alloc r32=ar.pfs,1,4,4,0 @@ -491,10 +491,10 @@ SPECIAL_log2f: br.ret.sptk b0;; } -GLOBAL_LIBM_END(__log2f) +WEAK_LIBM_END(log2f) libm_alias_float_other (__log2, log2) #ifdef SHARED -.symver __log2f,log2f@@GLIBC_2.27 +.symver log2f,log2f@@GLIBC_2.27 .weak __log2f_compat .set __log2f_compat,__log2f .symver __log2f_compat,log2f@GLIBC_2.2 diff --git a/sysdeps/ia64/fpu/e_powf.S b/sysdeps/ia64/fpu/e_powf.S index 7449f8c7d5..945d5cdf28 100644 --- a/sysdeps/ia64/fpu/e_powf.S +++ b/sysdeps/ia64/fpu/e_powf.S @@ -868,7 +868,7 @@ data8 0xEAC0C6E7DD24392F , 0x00003FFF LOCAL_OBJECT_END(pow_tbl2) .section .text -GLOBAL_LIBM_ENTRY(__powf) +WEAK_LIBM_ENTRY(powf) // Get exponent of x. Will be used to calculate K. { .mfi @@ -2002,10 +2002,10 @@ POW_OVER_UNDER_ERROR: } ;; -GLOBAL_LIBM_END(__powf) +WEAK_LIBM_END(powf) libm_alias_float_other (__pow, pow) #ifdef SHARED -.symver __powf,powf@@GLIBC_2.27 +.symver powf,powf@@GLIBC_2.27 .weak __powf_compat .set __powf_compat,__powf .symver __powf_compat,powf@GLIBC_2.2 diff --git a/sysdeps/ieee754/soft-fp/s_fdiv.c b/sysdeps/ieee754/soft-fp/s_fdiv.c index 341339f5ed..7a15cbeee6 100644 --- a/sysdeps/ieee754/soft-fp/s_fdiv.c +++ b/sysdeps/ieee754/soft-fp/s_fdiv.c @@ -25,6 +25,16 @@ #undef fdivl #include +#include + +/* R_f[01] are not set in cases where they are not used in packing, + but the compiler does not see that they are set in all cases where + they are used, resulting in warnings that they may be used + uninitialized. The location of the warning differs in different + versions of GCC, it may be where R is defined using a macro or it + may be where the macro is defined. This happens only with -O1. */ +DIAG_PUSH_NEEDS_COMMENT; +DIAG_IGNORE_NEEDS_COMMENT (8, "-Wmaybe-uninitialized"); #include #include #include @@ -53,4 +63,6 @@ __fdiv (double x, double y) CHECK_NARROW_DIV (ret, x, y); return ret; } +DIAG_POP_NEEDS_COMMENT; + libm_alias_float_double (div) diff --git a/sysdeps/nptl/bits/thread-shared-types.h b/sysdeps/nptl/bits/thread-shared-types.h index 1e2092a05d..05c94e7a71 100644 --- a/sysdeps/nptl/bits/thread-shared-types.h +++ b/sysdeps/nptl/bits/thread-shared-types.h @@ -124,7 +124,27 @@ struct __pthread_mutex_s unsigned int __nusers; #endif /* KIND must stay at this position in the structure to maintain - binary compatibility with static initializers. */ + binary compatibility with static initializers. + + Concurrency notes: + The __kind of a mutex is initialized either by the static + PTHREAD_MUTEX_INITIALIZER or by a call to pthread_mutex_init. + + After a mutex has been initialized, the __kind of a mutex is usually not + changed. BUT it can be set to -1 in pthread_mutex_destroy or elision can + be enabled. This is done concurrently in the pthread_mutex_*lock functions + by using the macro FORCE_ELISION. This macro is only defined for + architectures which supports lock elision. + + For elision, there are the flags PTHREAD_MUTEX_ELISION_NP and + PTHREAD_MUTEX_NO_ELISION_NP which can be set in addition to the already set + type of a mutex. + Before a mutex is initialized, only PTHREAD_MUTEX_NO_ELISION_NP can be set + with pthread_mutexattr_settype. + After a mutex has been initialized, the functions pthread_mutex_*lock can + enable elision - if the mutex-type and the machine supports it - by setting + the flag PTHREAD_MUTEX_ELISION_NP. This is done concurrently. Afterwards + the lock / unlock functions are using specific elision code-paths. */ int __kind; __PTHREAD_COMPAT_PADDING_MID #if __PTHREAD_MUTEX_NUSERS_AFTER_KIND diff --git a/sysdeps/nptl/fork.c b/sysdeps/nptl/fork.c index ec56a827eb..1a9429b579 100644 --- a/sysdeps/nptl/fork.c +++ b/sysdeps/nptl/fork.c @@ -55,7 +55,7 @@ __libc_fork (void) but our current fork implementation is not. */ bool multiple_threads = THREAD_GETMEM (THREAD_SELF, header.multiple_threads); - __run_fork_handlers (atfork_run_prepare); + __run_fork_handlers (atfork_run_prepare, multiple_threads); /* If we are not running multiple threads, we do not have to preserve lock state. If fork runs from a signal handler, only @@ -134,7 +134,7 @@ __libc_fork (void) __rtld_lock_initialize (GL(dl_load_lock)); /* Run the handlers registered for the child. */ - __run_fork_handlers (atfork_run_child); + __run_fork_handlers (atfork_run_child, multiple_threads); } else { @@ -149,7 +149,7 @@ __libc_fork (void) } /* Run the handlers registered for the parent. */ - __run_fork_handlers (atfork_run_parent); + __run_fork_handlers (atfork_run_parent, multiple_threads); } return pid; diff --git a/sysdeps/nptl/fork.h b/sysdeps/nptl/fork.h index 6eab61c121..bef2b7a8a6 100644 --- a/sysdeps/nptl/fork.h +++ b/sysdeps/nptl/fork.h @@ -52,9 +52,11 @@ enum __run_fork_handler_type - atfork_run_child: run all the CHILD_HANDLER and unlocks the internal lock. - atfork_run_parent: run all the PARENT_HANDLER and unlocks the internal - lock. */ -extern void __run_fork_handlers (enum __run_fork_handler_type who) - attribute_hidden; + lock. + + Perform locking only if DO_LOCKING. */ +extern void __run_fork_handlers (enum __run_fork_handler_type who, + _Bool do_locking) attribute_hidden; /* C library side function to register new fork handlers. */ extern int __register_atfork (void (*__prepare) (void), diff --git a/sysdeps/nptl/futex-internal.h b/sysdeps/nptl/futex-internal.h index 1a5624789d..6fd27f0df6 100644 --- a/sysdeps/nptl/futex-internal.h +++ b/sysdeps/nptl/futex-internal.h @@ -197,7 +197,7 @@ futex_wake (unsigned int* futex_word, int processes_to_wake, int private); static __always_inline __attribute__ ((__noreturn__)) void futex_fatal_error (void) { - __libc_fatal ("The futex facility returned an unexpected error code."); + __libc_fatal ("The futex facility returned an unexpected error code.\n"); } #endif /* futex-internal.h */ diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c index 553833d1f2..c91b281e31 100644 --- a/sysdeps/posix/getaddrinfo.c +++ b/sysdeps/posix/getaddrinfo.c @@ -488,7 +488,7 @@ gaih_inet (const char *name, const struct gaih_service *service, malloc_name = true; } - if (__inet_aton (name, (struct in_addr *) at->addr) != 0) + if (__inet_aton_exact (name, (struct in_addr *) at->addr) != 0) { if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET) at->family = AF_INET; diff --git a/sysdeps/powerpc/nptl/tcb-offsets.sym b/sysdeps/powerpc/nptl/tcb-offsets.sym index e5bb2b376d..4c01615ad0 100644 --- a/sysdeps/powerpc/nptl/tcb-offsets.sym +++ b/sysdeps/powerpc/nptl/tcb-offsets.sym @@ -21,7 +21,6 @@ DSO_SLOT2 (offsetof (tcbhead_t, dso_slot2) - TLS_TCB_OFFSET - sizeof (tcbhead_ #ifdef __powerpc64__ TCB_AT_PLATFORM (offsetof (tcbhead_t, at_platform) - TLS_TCB_OFFSET - sizeof(tcbhead_t)) #endif -TM_CAPABLE (offsetof (tcbhead_t, tm_capable) - TLS_TCB_OFFSET - sizeof (tcbhead_t)) #ifndef __powerpc64__ TCB_AT_PLATFORM (offsetof (tcbhead_t, at_platform) - TLS_TCB_OFFSET - sizeof(tcbhead_t)) PADDING (offsetof (tcbhead_t, padding) - TLS_TCB_OFFSET - sizeof(tcbhead_t)) diff --git a/sysdeps/powerpc/nptl/tls.h b/sysdeps/powerpc/nptl/tls.h index f88fed5ecf..8317ca7cfa 100644 --- a/sysdeps/powerpc/nptl/tls.h +++ b/sysdeps/powerpc/nptl/tls.h @@ -67,8 +67,7 @@ typedef struct uint32_t padding; uint32_t at_platform; #endif - /* Indicate if HTM capable (ISA 2.07). */ - uint32_t tm_capable; + uint32_t __unused; /* Reservation for AT_PLATFORM data - powerpc64. */ #ifdef __powerpc64__ uint32_t at_platform; @@ -142,7 +141,6 @@ register void *__thread_register __asm__ ("r13"); # define TLS_INIT_TP(tcbp) \ ({ \ __thread_register = (void *) (tcbp) + TLS_TCB_OFFSET; \ - THREAD_SET_TM_CAPABLE (__tcb_hwcap & PPC_FEATURE2_HAS_HTM ? 1 : 0); \ THREAD_SET_HWCAP (__tcb_hwcap); \ THREAD_SET_AT_PLATFORM (__tcb_platform); \ NULL; \ @@ -151,8 +149,6 @@ register void *__thread_register __asm__ ("r13"); /* Value passed to 'clone' for initialization of the thread register. */ # define TLS_DEFINE_INIT_TP(tp, pd) \ void *tp = (void *) (pd) + TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE; \ - (((tcbhead_t *) ((char *) tp - TLS_TCB_OFFSET))[-1].tm_capable) = \ - THREAD_GET_TM_CAPABLE (); \ (((tcbhead_t *) ((char *) tp - TLS_TCB_OFFSET))[-1].hwcap) = \ THREAD_GET_HWCAP (); \ (((tcbhead_t *) ((char *) tp - TLS_TCB_OFFSET))[-1].at_platform) = \ @@ -210,13 +206,6 @@ register void *__thread_register __asm__ ("r13"); + TLS_PRE_TCB_SIZE))[-1].pointer_guard \ = THREAD_GET_POINTER_GUARD()) -/* tm_capable field in TCB head. */ -# define THREAD_GET_TM_CAPABLE() \ - (((tcbhead_t *) ((char *) __thread_register \ - - TLS_TCB_OFFSET))[-1].tm_capable) -# define THREAD_SET_TM_CAPABLE(value) \ - (THREAD_GET_TM_CAPABLE () = (value)) - /* hwcap field in TCB head. */ # define THREAD_GET_HWCAP() \ (((tcbhead_t *) ((char *) __thread_register \ diff --git a/sysdeps/powerpc/powerpc32/dl-irel.h b/sysdeps/powerpc/powerpc32/dl-irel.h index a7368b2582..61d0e4cf61 100644 --- a/sysdeps/powerpc/powerpc32/dl-irel.h +++ b/sysdeps/powerpc/powerpc32/dl-irel.h @@ -46,7 +46,7 @@ elf_irela (const Elf32_Rela *reloc) *reloc_addr = value; } else - __libc_fatal ("unexpected reloc type in static binary"); + __libc_fatal ("Unexpected reloc type in static binary.\n"); } #endif /* dl-irel.h */ diff --git a/sysdeps/powerpc/powerpc32/sysdep.h b/sysdeps/powerpc/powerpc32/sysdep.h index 5f1294ead3..93097c5459 100644 --- a/sysdeps/powerpc/powerpc32/sysdep.h +++ b/sysdeps/powerpc/powerpc32/sysdep.h @@ -90,24 +90,7 @@ GOT_LABEL: ; \ cfi_endproc; \ ASM_SIZE_DIRECTIVE(name) -#if !IS_IN(rtld) && !defined(__SPE__) -# define ABORT_TRANSACTION_IMPL \ - cmpwi 2,0; \ - beq 1f; \ - lwz 0,TM_CAPABLE(2); \ - cmpwi 0,0; \ - beq 1f; \ - li 11,_ABORT_SYSCALL; \ - tabort. 11; \ - .align 4; \ -1: -#else -# define ABORT_TRANSACTION_IMPL -#endif -#define ABORT_TRANSACTION ABORT_TRANSACTION_IMPL - #define DO_CALL(syscall) \ - ABORT_TRANSACTION \ li 0,syscall; \ sc diff --git a/sysdeps/powerpc/powerpc64/addmul_1.S b/sysdeps/powerpc/powerpc64/addmul_1.S index 48e3b1b290..e450d6a52c 100644 --- a/sysdeps/powerpc/powerpc64/addmul_1.S +++ b/sysdeps/powerpc/powerpc64/addmul_1.S @@ -34,16 +34,27 @@ #define N r5 #define VL r6 +#define R27SAVE (-40) +#define R28SAVE (-32) +#define R29SAVE (-24) +#define R30SAVE (-16) +#define R31SAVE (-8) + ENTRY_TOCLESS (FUNC, 5) - std r31, -8(r1) + std r31, R31SAVE(r1) rldicl. r0, N, 0, 62 - std r30, -16(r1) + std r30, R30SAVE(r1) cmpdi VL, r0, 2 - std r29, -24(r1) + std r29, R29SAVE(r1) addi N, N, 3 - std r28, -32(r1) + std r28, R28SAVE(r1) srdi N, N, 2 - std r27, -40(r1) + std r27, R27SAVE(r1) + cfi_offset(r31, R31SAVE) + cfi_offset(r30, R30SAVE) + cfi_offset(r29, R29SAVE) + cfi_offset(r28, R28SAVE) + cfi_offset(r27, R27SAVE) mtctr N beq cr0, L(b00) blt cr6, L(b01) @@ -199,10 +210,10 @@ L(end): mulld r0, r9, VL addic r11, r11, 1 #endif addze RP, r8 - ld r31, -8(r1) - ld r30, -16(r1) - ld r29, -24(r1) - ld r28, -32(r1) - ld r27, -40(r1) + ld r31, R31SAVE(r1) + ld r30, R30SAVE(r1) + ld r29, R29SAVE(r1) + ld r28, R28SAVE(r1) + ld r27, R27SAVE(r1) blr END(FUNC) diff --git a/sysdeps/powerpc/powerpc64/dl-irel.h b/sysdeps/powerpc/powerpc64/dl-irel.h index ab13c04358..2fd0ee8a86 100644 --- a/sysdeps/powerpc/powerpc64/dl-irel.h +++ b/sysdeps/powerpc/powerpc64/dl-irel.h @@ -57,7 +57,7 @@ elf_irela (const Elf64_Rela *reloc) #endif } else - __libc_fatal ("unexpected reloc type in static binary"); + __libc_fatal ("Unexpected reloc type in static binary.\n"); } #endif /* dl-irel.h */ diff --git a/sysdeps/powerpc/powerpc64/lshift.S b/sysdeps/powerpc/powerpc64/lshift.S index 8b6396ee6c..855d6f2993 100644 --- a/sysdeps/powerpc/powerpc64/lshift.S +++ b/sysdeps/powerpc/powerpc64/lshift.S @@ -26,11 +26,15 @@ #define TNC r0 #define U0 r30 #define U1 r31 +#define U0SAVE (-16) +#define U1SAVE (-8) #define RETVAL r5 ENTRY_TOCLESS (__mpn_lshift, 5) - std U1, -8(r1) - std U0, -16(r1) + std U1, U1SAVE(r1) + std U0, U0SAVE(r1) + cfi_offset(U1, U1SAVE) + cfi_offset(U0, U0SAVE) subfic TNC, CNT, 64 sldi r7, N, RP add UP, UP, r7 @@ -170,8 +174,8 @@ L(cj3): or r10, r12, r7 L(cj2): std r10, -32(RP) std r8, -40(RP) -L(ret): ld U1, -8(r1) - ld U0, -16(r1) +L(ret): ld U1, U1SAVE(r1) + ld U0, U0SAVE(r1) mr RP, RETVAL blr END(__mpn_lshift) diff --git a/sysdeps/powerpc/powerpc64/mul_1.S b/sysdeps/powerpc/powerpc64/mul_1.S index 953ded8028..cade365258 100644 --- a/sysdeps/powerpc/powerpc64/mul_1.S +++ b/sysdeps/powerpc/powerpc64/mul_1.S @@ -24,9 +24,14 @@ #define N r5 #define VL r6 +#define R26SAVE (-48) +#define R27SAVE (-40) + ENTRY_TOCLESS (__mpn_mul_1, 5) - std r27, -40(r1) - std r26, -48(r1) + std r27, R27SAVE(r1) + std r26, R26SAVE(r1) + cfi_offset(r27, R27SAVE) + cfi_offset(r26, R26SAVE) li r12, 0 ld r26, 0(UP) @@ -129,7 +134,7 @@ L(end): mulld r0, r26, VL std r0, 0(RP) std r7, 8(RP) L(ret): addze RP, r8 - ld r27, -40(r1) - ld r26, -48(r1) + ld r27, R27SAVE(r1) + ld r26, R26SAVE(r1) blr END(__mpn_mul_1) diff --git a/sysdeps/powerpc/powerpc64/sysdep.h b/sysdeps/powerpc/powerpc64/sysdep.h index 2df1d9b6e6..50e64f9ce2 100644 --- a/sysdeps/powerpc/powerpc64/sysdep.h +++ b/sysdeps/powerpc/powerpc64/sysdep.h @@ -263,24 +263,7 @@ LT_LABELSUFFIX(name,_name_end): ; \ TRACEBACK_MASK(name,mask); \ END_2(name) -#if !IS_IN(rtld) -# define ABORT_TRANSACTION_IMPL \ - cmpdi 13,0; \ - beq 1f; \ - lwz 0,TM_CAPABLE(13); \ - cmpwi 0,0; \ - beq 1f; \ - li 11,_ABORT_SYSCALL; \ - tabort. 11; \ - .p2align 4; \ -1: -#else -# define ABORT_TRANSACTION_IMPL -#endif -#define ABORT_TRANSACTION ABORT_TRANSACTION_IMPL - #define DO_CALL(syscall) \ - ABORT_TRANSACTION \ li 0,syscall; \ sc diff --git a/sysdeps/powerpc/sysdep.h b/sysdeps/powerpc/sysdep.h index 8a6d236caa..c8bf25e870 100644 --- a/sysdeps/powerpc/sysdep.h +++ b/sysdeps/powerpc/sysdep.h @@ -21,8 +21,6 @@ */ #define _SYSDEPS_SYSDEP_H 1 #include -#include -#include #define PPC_FEATURE_970 (PPC_FEATURE_POWER4 + PPC_FEATURE_HAS_ALTIVEC) @@ -166,22 +164,4 @@ #define ALIGNARG(log2) log2 #define ASM_SIZE_DIRECTIVE(name) .size name,.-name -#else - -/* Linux kernel powerpc documentation [1] states issuing a syscall inside a - transaction is not recommended and may lead to undefined behavior. It - also states syscalls do not abort transactions. To avoid such traps, - we abort transaction just before syscalls. - - [1] Documentation/powerpc/transactional_memory.txt [Syscalls] */ -#if !IS_IN(rtld) && !defined(__SPE__) -# define ABORT_TRANSACTION \ - ({ \ - if (THREAD_GET_TM_CAPABLE ()) \ - __libc_tabort (_ABORT_SYSCALL); \ - }) -#else -# define ABORT_TRANSACTION -#endif - #endif /* __ASSEMBLER__ */ diff --git a/sysdeps/riscv/rv64/rvd/libm-test-ulps b/sysdeps/riscv/rv64/rvd/libm-test-ulps index f8feadcd0d..61be2df60d 100644 --- a/sysdeps/riscv/rv64/rvd/libm-test-ulps +++ b/sysdeps/riscv/rv64/rvd/libm-test-ulps @@ -1006,6 +1006,8 @@ ildouble: 2 ldouble: 2 Function: "cos": +double: 1 +idouble: 1 ildouble: 1 ldouble: 1 @@ -1348,9 +1350,9 @@ ildouble: 4 ldouble: 4 Function: Imaginary part of "ctan_towardzero": -double: 1 +double: 2 float: 2 -idouble: 1 +idouble: 2 ifloat: 2 ildouble: 5 ldouble: 5 @@ -1898,10 +1900,12 @@ ldouble: 2 Function: "log_upward": double: 1 idouble: 1 -ildouble: 1 -ldouble: 1 +ildouble: 2 +ldouble: 2 Function: "pow": +double: 1 +idouble: 1 ildouble: 2 ldouble: 2 @@ -1930,6 +1934,8 @@ ildouble: 2 ldouble: 2 Function: "sin": +double: 1 +idouble: 1 ildouble: 1 ldouble: 1 @@ -1952,6 +1958,8 @@ ildouble: 3 ldouble: 3 Function: "sincos": +double: 1 +idouble: 1 ildouble: 1 ldouble: 1 diff --git a/sysdeps/riscv/rvf/math_private.h b/sysdeps/riscv/rvf/math_private.h index cdb7858fc8..ca587620cb 100644 --- a/sysdeps/riscv/rvf/math_private.h +++ b/sysdeps/riscv/rvf/math_private.h @@ -72,8 +72,8 @@ libc_fesetround_riscv (int round) static __always_inline void libc_feholdexcept_setround_riscv (fenv_t *envp, int round) { - libc_fesetround_riscv (round); libc_feholdexcept_riscv (envp); + libc_fesetround_riscv (round); } #define libc_feholdexcept_setround libc_feholdexcept_setround_riscv diff --git a/sysdeps/riscv/start.S b/sysdeps/riscv/start.S index 4635ddb5eb..2d6f06e630 100644 --- a/sysdeps/riscv/start.S +++ b/sysdeps/riscv/start.S @@ -43,6 +43,10 @@ __libc_start_main wants this in a5. */ ENTRY (ENTRY_POINT) + /* Terminate call stack by noting ra is undefined. Use a dummy + .cfi_label to force starting the FDE. */ + .cfi_label .Ldummy + cfi_undefined (ra) call .Lload_gp mv a5, a0 /* rtld_fini. */ /* main may be in a shared library. */ @@ -54,7 +58,8 @@ ENTRY (ENTRY_POINT) lla a4, __libc_csu_fini mv a6, sp /* stack_end. */ - tail __libc_start_main@plt + call __libc_start_main@plt + ebreak END (ENTRY_POINT) /* Dynamic links need the global pointer to be initialized prior to calling diff --git a/sysdeps/s390/dl-irel.h b/sysdeps/s390/dl-irel.h index d8ba7ba427..ecb24f0a9b 100644 --- a/sysdeps/s390/dl-irel.h +++ b/sysdeps/s390/dl-irel.h @@ -46,7 +46,7 @@ elf_irela (const ElfW(Rela) *reloc) *reloc_addr = value; } else - __libc_fatal ("unexpected reloc type in static binary"); + __libc_fatal ("Unexpected reloc type in static binary.\n"); } #endif /* dl-irel.h */ diff --git a/sysdeps/s390/dl-procinfo.h b/sysdeps/s390/dl-procinfo.h index b0383bfb4c..f71d64c3ab 100644 --- a/sysdeps/s390/dl-procinfo.h +++ b/sysdeps/s390/dl-procinfo.h @@ -57,7 +57,8 @@ enum }; #define HWCAP_IMPORTANT (HWCAP_S390_ZARCH | HWCAP_S390_LDISP \ - | HWCAP_S390_EIMM | HWCAP_S390_DFP) + | HWCAP_S390_EIMM | HWCAP_S390_DFP \ + | HWCAP_S390_VX | HWCAP_S390_VXE) /* We cannot provide a general printing function. */ #define _dl_procinfo(type, word) -1 diff --git a/sysdeps/sparc/sparc32/dl-irel.h b/sysdeps/sparc/sparc32/dl-irel.h index ffca36864f..cf47cda834 100644 --- a/sysdeps/sparc/sparc32/dl-irel.h +++ b/sysdeps/sparc/sparc32/dl-irel.h @@ -56,7 +56,7 @@ elf_irela (const Elf32_Rela *reloc) else if (r_type == R_SPARC_NONE) ; else - __libc_fatal ("unexpected reloc type in static binary"); + __libc_fatal ("Unexpected reloc type in static binary.\n"); } #endif /* dl-irel.h */ diff --git a/sysdeps/sparc/sparc64/dl-irel.h b/sysdeps/sparc/sparc64/dl-irel.h index c5cd3057ac..446fed1836 100644 --- a/sysdeps/sparc/sparc64/dl-irel.h +++ b/sysdeps/sparc/sparc64/dl-irel.h @@ -59,7 +59,7 @@ elf_irela (const Elf64_Rela *reloc) else if (r_type == R_SPARC_NONE) ; else - __libc_fatal ("unexpected reloc type in static binary"); + __libc_fatal ("Unexpected reloc type in static binary.\n"); } #endif /* dl-irel.h */ diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile index f71cc39c7e..773aaea0e9 100644 --- a/sysdeps/unix/sysv/linux/Makefile +++ b/sysdeps/unix/sysv/linux/Makefile @@ -161,6 +161,7 @@ inhibit-glue = yes ifeq ($(subdir),dirent) sysdep_routines += getdirentries getdirentries64 +tests-internal += tst-readdir64-compat endif ifeq ($(subdir),nis) diff --git a/sysdeps/unix/sysv/linux/arm/atomic-machine.h b/sysdeps/unix/sysv/linux/arm/atomic-machine.h index ad165274d8..a5d244e65e 100644 --- a/sysdeps/unix/sysv/linux/arm/atomic-machine.h +++ b/sysdeps/unix/sysv/linux/arm/atomic-machine.h @@ -49,16 +49,23 @@ declarations of A_OLDVAL et al because when NEWVAL or OLDVAL is of the form *PTR and PTR has a 'volatile ... *' type, then __typeof (*PTR) has a 'volatile ...' type and this triggers -Wvolatile-register-var to - complain about 'register volatile ... asm ("reg")'. */ + complain about 'register volatile ... asm ("reg")'. + + We use the same union trick in the declaration of A_PTR because when + MEM is of the from *PTR and PTR has a 'const ... *' type, then __typeof + (*PTR) has a 'const ...' type and this enables the compiler to substitute + the variable with its initializer in asm statements, which may cause the + corresponding operand to appear in a different register. */ #ifdef __thumb2__ /* Thumb-2 has ldrex/strex. However it does not have barrier instructions, so we still need to use the kernel helper. */ # define __arm_assisted_compare_and_exchange_val_32_acq(mem, newval, oldval) \ - ({ union { __typeof (oldval) a; uint32_t v; } oldval_arg = { .a = (oldval) };\ + ({ union { __typeof (mem) a; uint32_t v; } mem_arg = { .a = (mem) }; \ + union { __typeof (oldval) a; uint32_t v; } oldval_arg = { .a = (oldval) };\ union { __typeof (newval) a; uint32_t v; } newval_arg = { .a = (newval) };\ register uint32_t a_oldval asm ("r0"); \ register uint32_t a_newval asm ("r1") = newval_arg.v; \ - register __typeof (mem) a_ptr asm ("r2") = (mem); \ + register uint32_t a_ptr asm ("r2") = mem_arg.v; \ register uint32_t a_tmp asm ("r3"); \ register uint32_t a_oldval2 asm ("r4") = oldval_arg.v; \ __asm__ __volatile__ \ @@ -79,11 +86,12 @@ (__typeof (oldval)) a_tmp; }) #else # define __arm_assisted_compare_and_exchange_val_32_acq(mem, newval, oldval) \ - ({ union { __typeof (oldval) a; uint32_t v; } oldval_arg = { .a = (oldval) };\ + ({ union { __typeof (mem) a; uint32_t v; } mem_arg = { .a = (mem) }; \ + union { __typeof (oldval) a; uint32_t v; } oldval_arg = { .a = (oldval) };\ union { __typeof (newval) a; uint32_t v; } newval_arg = { .a = (newval) };\ register uint32_t a_oldval asm ("r0"); \ register uint32_t a_newval asm ("r1") = newval_arg.v; \ - register __typeof (mem) a_ptr asm ("r2") = (mem); \ + register uint32_t a_ptr asm ("r2") = mem_arg.v; \ register uint32_t a_tmp asm ("r3"); \ register uint32_t a_oldval2 asm ("r4") = oldval_arg.v; \ __asm__ __volatile__ \ diff --git a/sysdeps/unix/sysv/linux/bits/types/siginfo_t.h b/sysdeps/unix/sysv/linux/bits/types/siginfo_t.h index 33766d1813..43c4e009a4 100644 --- a/sysdeps/unix/sysv/linux/bits/types/siginfo_t.h +++ b/sysdeps/unix/sysv/linux/bits/types/siginfo_t.h @@ -107,7 +107,7 @@ typedef struct /* SIGPOLL. */ struct { - long int si_band; /* Band event for SIGPOLL. */ + __SI_BAND_TYPE si_band; /* Band event for SIGPOLL. */ int si_fd; } _sigpoll; diff --git a/sysdeps/unix/sysv/linux/getdents64.c b/sysdeps/unix/sysv/linux/getdents64.c index 3bde0cf4f0..46eb5f4419 100644 --- a/sysdeps/unix/sysv/linux/getdents64.c +++ b/sysdeps/unix/sysv/linux/getdents64.c @@ -33,41 +33,90 @@ strong_alias (__getdents64, __getdents) # include # if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2) -# include +# include +# include -/* kernel definition of as of 3.2. */ -struct compat_linux_dirent +static ssize_t +handle_overflow (int fd, __off64_t offset, ssize_t count) { - /* Both d_ino and d_off are compat_ulong_t which are defined in all - architectures as 'u32'. */ - uint32_t d_ino; - uint32_t d_off; - unsigned short d_reclen; - char d_name[1]; -}; + /* If this is the first entry in the buffer, we can report the + error. */ + if (offset == 0) + { + __set_errno (EOVERFLOW); + return -1; + } + + /* Otherwise, seek to the overflowing entry, so that the next call + will report the error, and return the data read so far. */ + if (__lseek64 (fd, offset, SEEK_SET) != 0) + return -1; + return count; +} ssize_t __old_getdents64 (int fd, char *buf, size_t nbytes) { - ssize_t retval = INLINE_SYSCALL_CALL (getdents, fd, buf, nbytes); + /* We do not move the individual directory entries. This is only + possible if the target type (struct __old_dirent64) is smaller + than the source type. */ + _Static_assert (offsetof (struct __old_dirent64, d_name) + <= offsetof (struct dirent64, d_name), + "__old_dirent64 is larger than dirent64"); + _Static_assert (__alignof__ (struct __old_dirent64) + <= __alignof__ (struct dirent64), + "alignment of __old_dirent64 is larger than dirent64"); - /* The kernel added the d_type value after the name. Change this now. */ - if (retval != -1) + ssize_t retval = INLINE_SYSCALL_CALL (getdents64, fd, buf, nbytes); + if (retval > 0) { - union - { - struct compat_linux_dirent k; - struct dirent u; - } *kbuf = (void *) buf; + /* This is the marker for the first entry. Offset 0 is reserved + for the first entry (see rewinddir). Here, we use it as a + marker for the first entry in the buffer. We never actually + seek to offset 0 because handle_overflow reports the error + directly, so it does not matter that the offset is incorrect + if entries have been read from the descriptor before (so that + the descriptor is not actually at offset 0). */ + __off64_t previous_offset = 0; - while ((char *) kbuf < buf + retval) + char *p = buf; + char *end = buf + retval; + while (p < end) { - char d_type = *((char *) kbuf + kbuf->k.d_reclen - 1); - memmove (kbuf->u.d_name, kbuf->k.d_name, - strlen (kbuf->k.d_name) + 1); - kbuf->u.d_type = d_type; + struct dirent64 *source = (struct dirent64 *) p; + + /* Copy out the fixed-size data. */ + __ino_t ino = source->d_ino; + __off64_t offset = source->d_off; + unsigned int reclen = source->d_reclen; + unsigned char type = source->d_type; + + /* Check for ino_t overflow. */ + if (__glibc_unlikely (ino != source->d_ino)) + return handle_overflow (fd, previous_offset, p - buf); + + /* Convert to the target layout. Use a separate struct and + memcpy to side-step aliasing issues. */ + struct __old_dirent64 result; + result.d_ino = ino; + result.d_off = offset; + result.d_reclen = reclen; + result.d_type = type; + + /* Write the fixed-sized part of the result to the + buffer. */ + size_t result_name_offset = offsetof (struct __old_dirent64, d_name); + memcpy (p, &result, result_name_offset); + + /* Adjust the position of the name if necessary. Copy + everything until the end of the record, including the + terminating NUL byte. */ + if (result_name_offset != offsetof (struct dirent64, d_name)) + memmove (p + result_name_offset, source->d_name, + reclen - offsetof (struct dirent64, d_name)); - kbuf = (void *) ((char *) kbuf + kbuf->k.d_reclen); + p += reclen; + previous_offset = offset; } } return retval; diff --git a/sysdeps/unix/sysv/linux/gethostid.c b/sysdeps/unix/sysv/linux/gethostid.c index 2e20f034dc..ee0190e7f9 100644 --- a/sysdeps/unix/sysv/linux/gethostid.c +++ b/sysdeps/unix/sysv/linux/gethostid.c @@ -102,12 +102,12 @@ gethostid (void) { int ret = __gethostbyname_r (hostname, &hostbuf, tmpbuf.data, tmpbuf.length, &hp, &herr); - if (ret == 0) + if (ret == 0 && hp != NULL) break; else { /* Enlarge the buffer on ERANGE. */ - if (herr == NETDB_INTERNAL && errno == ERANGE) + if (ret != 0 && herr == NETDB_INTERNAL && errno == ERANGE) { if (!scratch_buffer_grow (&tmpbuf)) return 0; diff --git a/sysdeps/unix/sysv/linux/if_index.c b/sysdeps/unix/sysv/linux/if_index.c index e3d08982d9..782fc5e175 100644 --- a/sysdeps/unix/sysv/linux/if_index.c +++ b/sysdeps/unix/sysv/linux/if_index.c @@ -38,11 +38,6 @@ __if_nametoindex (const char *ifname) return 0; #else struct ifreq ifr; - int fd = __opensock (); - - if (fd < 0) - return 0; - if (strlen (ifname) >= IFNAMSIZ) { __set_errno (ENODEV); @@ -50,6 +45,12 @@ __if_nametoindex (const char *ifname) } strncpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); + + int fd = __opensock (); + + if (fd < 0) + return 0; + if (__ioctl (fd, SIOCGIFINDEX, &ifr) < 0) { int saved_errno = errno; diff --git a/sysdeps/unix/sysv/linux/kernel_sigaction.h b/sysdeps/unix/sysv/linux/kernel_sigaction.h index 2dbec08099..1c36146d46 100644 --- a/sysdeps/unix/sysv/linux/kernel_sigaction.h +++ b/sysdeps/unix/sysv/linux/kernel_sigaction.h @@ -1,19 +1,27 @@ #ifndef _KERNEL_SIGACTION_H # define _KERNEL_SIGACTION_H +#ifdef SA_RESTORER +# define HAS_SA_RESTORER 1 +#endif + /* This is the sigaction structure from the Linux 3.2 kernel. */ struct kernel_sigaction { __sighandler_t k_sa_handler; unsigned long sa_flags; -#ifdef SA_RESTORER +#ifdef HAS_SA_RESTORER void (*sa_restorer) (void); #endif + /* glibc sigset is larger than kernel expected one, however sigaction + passes the kernel expected size on rt_sigaction syscall. */ sigset_t sa_mask; }; -#ifndef SA_RESTORER +#ifndef SET_SA_RESTORER # define SET_SA_RESTORER(kact, act) +#endif +#ifndef RESET_SA_RESTORER # define RESET_SA_RESTORER(act, kact) #endif diff --git a/sysdeps/unix/sysv/linux/m68k/kernel_sigaction.h b/sysdeps/unix/sysv/linux/m68k/kernel_sigaction.h index 54972feb13..464b351d6d 100644 --- a/sysdeps/unix/sysv/linux/m68k/kernel_sigaction.h +++ b/sysdeps/unix/sysv/linux/m68k/kernel_sigaction.h @@ -1,22 +1,4 @@ -#ifndef _KERNEL_SIGACTION_H -# define _KERNEL_SIGACTION_H - -#include - -#define SA_RESTORER 0x04000000 - -/* This is the sigaction structure from the Linux 3.2 kernel. */ -struct kernel_sigaction -{ - __sighandler_t k_sa_handler; - sigset_t sa_mask; - unsigned long sa_flags; - void (*sa_restorer) (void); -}; - -#define SET_SA_RESTORER(kact, act) \ - (kact)->sa_restorer = (act)->sa_restorer -#define RESET_SA_RESTORER(act, kact) \ - (act)->sa_restorer = (kact)->sa_restorer - -#endif +/* m68k does not define SA_RESTORER, but does have sa_restorer member + on kernel sigaction struct. */ +#define HAS_SA_RESTORER 1 +#include diff --git a/sysdeps/unix/sysv/linux/netlink_assert_response.c b/sysdeps/unix/sysv/linux/netlink_assert_response.c index f31ccb52ff..6afc3a17ce 100644 --- a/sysdeps/unix/sysv/linux/netlink_assert_response.c +++ b/sysdeps/unix/sysv/linux/netlink_assert_response.c @@ -72,12 +72,12 @@ __netlink_assert_response (int fd, ssize_t result) char message[200]; if (family < 0) __snprintf (message, sizeof (message), - "Unexpected error %d on netlink descriptor %d", + "Unexpected error %d on netlink descriptor %d.\n", error_code, fd); else __snprintf (message, sizeof (message), "Unexpected error %d on netlink descriptor %d" - " (address family %d)", + " (address family %d).\n", error_code, fd, family); __libc_fatal (message); } diff --git a/sysdeps/unix/sysv/linux/nios2/kernel_sigaction.h b/sysdeps/unix/sysv/linux/nios2/kernel_sigaction.h index 4ada322104..89f9bcedfd 100644 --- a/sysdeps/unix/sysv/linux/nios2/kernel_sigaction.h +++ b/sysdeps/unix/sysv/linux/nios2/kernel_sigaction.h @@ -1,8 +1,9 @@ /* NIOS2 uses the generic Linux UAPI but defines SA_RESTORER. */ #define SA_RESTORER 0x04000000 -#include #define SET_SA_RESTORER(kact, act) \ (kact)->sa_restorer = (act)->sa_restorer #define RESET_SA_RESTORER(act, kact) \ (act)->sa_restorer = (kact)->sa_restorer + +#include diff --git a/sysdeps/unix/sysv/linux/powerpc/elision-conf.c b/sysdeps/unix/sysv/linux/powerpc/elision-conf.c index 906882a65e..fc82bd1ad8 100644 --- a/sysdeps/unix/sysv/linux/powerpc/elision-conf.c +++ b/sysdeps/unix/sysv/linux/powerpc/elision-conf.c @@ -127,6 +127,26 @@ elision_init (int argc __attribute__ ((unused)), TUNABLE_CALLBACK (set_elision_skip_trylock_internal_abort)); #endif + /* Linux from 3.9 through 4.2 do not abort HTM transaction on syscalls, + instead it suspends the transaction and resumes it when returning to + usercode. The side-effects of the syscall will always remain visible, + even if the transaction is aborted. This is an issue when a transaction + is used along with futex syscall, on pthread_cond_wait for instance, + where futex might succeed but the transaction is rolled back leading + the condition variable object in an inconsistent state. + + Glibc used to prevent it by always aborting a transaction before issuing + a syscall. Linux 4.2 also decided to abort active transaction in + syscalls which makes the glibc workaround superflours. Worse, glibc + transaction abortions leads to a performance issues on recent kernels. + + So Lock Elision is just enabled when it has been explict set (either + by tunables of by a configure switch) and if kernel aborts HTM + transactions on syscalls (PPC_FEATURE2_HTM_NOSC) */ + + __pthread_force_elision = (__pthread_force_elision + && GLRO (dl_hwcap2) & PPC_FEATURE2_HTM_NOSC); + if (!__pthread_force_elision) __elision_aconf.try_tbegin = 0; /* Disable elision on rwlocks. */ } diff --git a/sysdeps/unix/sysv/linux/powerpc/force-elision.h b/sysdeps/unix/sysv/linux/powerpc/force-elision.h index fe5d6ceade..d8f5a4b1c7 100644 --- a/sysdeps/unix/sysv/linux/powerpc/force-elision.h +++ b/sysdeps/unix/sysv/linux/powerpc/force-elision.h @@ -18,9 +18,45 @@ /* Automatically enable elision for existing user lock kinds. */ #define FORCE_ELISION(m, s) \ - if (__pthread_force_elision \ - && (m->__data.__kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0) \ + if (__pthread_force_elision) \ { \ - mutex->__data.__kind |= PTHREAD_MUTEX_ELISION_NP; \ - s; \ + /* See concurrency notes regarding __kind in \ + struct __pthread_mutex_s in \ + sysdeps/nptl/bits/thread-shared-types.h. \ + \ + There are the following cases for the kind of a mutex \ + (The mask PTHREAD_MUTEX_ELISION_FLAGS_NP covers the flags \ + PTHREAD_MUTEX_ELISION_NP and PTHREAD_MUTEX_NO_ELISION_NP where \ + only one of both flags can be set): \ + - both flags are not set: \ + This is the first lock operation for this mutex. Enable \ + elision as it is not enabled so far. \ + Note: It can happen that multiple threads are calling e.g. \ + pthread_mutex_lock at the same time as the first lock \ + operation for this mutex. Then elision is enabled for this \ + mutex by multiple threads. Storing with relaxed MO is enough \ + as all threads will store the same new value for the kind of \ + the mutex. But we have to ensure that we always use the \ + elision path regardless if this thread has enabled elision or \ + another one. \ + \ + - PTHREAD_MUTEX_ELISION_NP flag is set: \ + Elision was already enabled for this mutex by a previous lock \ + operation. See case above. Just use the elision path. \ + \ + - PTHREAD_MUTEX_NO_ELISION_NP flag is set: \ + Elision was explicitly disabled by pthread_mutexattr_settype. \ + Do not use the elision path. \ + Note: The flag PTHREAD_MUTEX_NO_ELISION_NP will never be \ + changed after mutex initialization. */ \ + int mutex_kind = atomic_load_relaxed (&((m)->__data.__kind)); \ + if ((mutex_kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0) \ + { \ + mutex_kind |= PTHREAD_MUTEX_ELISION_NP; \ + atomic_store_relaxed (&((m)->__data.__kind), mutex_kind); \ + } \ + if ((mutex_kind & PTHREAD_MUTEX_ELISION_NP) != 0) \ + { \ + s; \ + } \ } diff --git a/sysdeps/unix/sysv/linux/powerpc/kernel_sigaction.h b/sysdeps/unix/sysv/linux/powerpc/kernel_sigaction.h index aef3d5a3b3..bac03ee45d 100644 --- a/sysdeps/unix/sysv/linux/powerpc/kernel_sigaction.h +++ b/sysdeps/unix/sysv/linux/powerpc/kernel_sigaction.h @@ -1,9 +1,10 @@ /* powerpc kernel sigaction is similar to generic Linux UAPI one, but the architecture also defines SA_RESTORER. */ #define SA_RESTORER 0x04000000 -#include #define SET_SA_RESTORER(kact, act) \ (kact)->sa_restorer = (act)->sa_restorer #define RESET_SA_RESTORER(act, kact) \ (act)->sa_restorer = (kact)->sa_restorer + +#include diff --git a/sysdeps/unix/sysv/linux/powerpc/not-errno.h b/sysdeps/unix/sysv/linux/powerpc/not-errno.h deleted file mode 100644 index 27da21bdf1..0000000000 --- a/sysdeps/unix/sysv/linux/powerpc/not-errno.h +++ /dev/null @@ -1,30 +0,0 @@ -/* Syscall wrapper that do not set errno. Linux powerpc version. - 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 - . */ - -/* __access_noerrno is used during process initialization in elf/dl-tunables.c - before the TCB is initialized, prohibiting the usage of - ABORT_TRANSACTION. */ -#undef ABORT_TRANSACTION -#define ABORT_TRANSACTION - -#include "sysdeps/unix/sysv/linux/not-errno.h" - -/* Recover ABORT_TRANSACTION's previous value, in order to not affect - other syscalls. */ -#undef ABORT_TRANSACTION -#define ABORT_TRANSACTION ABORT_TRANSACTION_IMPL diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h b/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h index f7277d59e1..ec5c5250f8 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h @@ -109,7 +109,6 @@ register long int r11 __asm__ ("r11"); \ register long int r12 __asm__ ("r12"); \ LOADARGS_##nr(name, args); \ - ABORT_TRANSACTION; \ __asm__ __volatile__ \ ("sc \n\t" \ "mfcr %0" \ diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h b/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h index 0956cf04a7..1f17f7bd5f 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h @@ -131,7 +131,6 @@ register long int r7 __asm__ ("r7"); \ register long int r8 __asm__ ("r8"); \ LOADARGS_##nr (name, ##args); \ - ABORT_TRANSACTION; \ __asm__ __volatile__ \ ("sc\n\t" \ "mfcr %0\n\t" \ diff --git a/sysdeps/unix/sysv/linux/powerpc/syscall.S b/sysdeps/unix/sysv/linux/powerpc/syscall.S index 2da91721be..bbab613aca 100644 --- a/sysdeps/unix/sysv/linux/powerpc/syscall.S +++ b/sysdeps/unix/sysv/linux/powerpc/syscall.S @@ -18,7 +18,6 @@ #include ENTRY (syscall) - ABORT_TRANSACTION mr r0,r3 mr r3,r4 mr r4,r5 diff --git a/sysdeps/unix/sysv/linux/preadv2.c b/sysdeps/unix/sysv/linux/preadv2.c index c8bf0764ef..bb08cbc5fd 100644 --- a/sysdeps/unix/sysv/linux/preadv2.c +++ b/sysdeps/unix/sysv/linux/preadv2.c @@ -32,7 +32,7 @@ preadv2 (int fd, const struct iovec *vector, int count, off_t offset, # ifdef __NR_preadv2 ssize_t result = SYSCALL_CANCEL (preadv2, fd, vector, count, LO_HI_LONG (offset), flags); - if (result >= 0) + if (result >= 0 || errno != ENOSYS) return result; # endif /* Trying to emulate the preadv2 syscall flags is troublesome: diff --git a/sysdeps/unix/sysv/linux/preadv64v2.c b/sysdeps/unix/sysv/linux/preadv64v2.c index d7400a0252..b72a047347 100644 --- a/sysdeps/unix/sysv/linux/preadv64v2.c +++ b/sysdeps/unix/sysv/linux/preadv64v2.c @@ -30,7 +30,7 @@ preadv64v2 (int fd, const struct iovec *vector, int count, off64_t offset, #ifdef __NR_preadv64v2 ssize_t result = SYSCALL_CANCEL (preadv64v2, fd, vector, count, LO_HI_LONG (offset), flags); - if (result >= 0) + if (result >= 0 || errno != ENOSYS) return result; #endif /* Trying to emulate the preadv2 syscall flags is troublesome: diff --git a/sysdeps/unix/sysv/linux/pwritev2.c b/sysdeps/unix/sysv/linux/pwritev2.c index 29c2264c8f..26333ebd43 100644 --- a/sysdeps/unix/sysv/linux/pwritev2.c +++ b/sysdeps/unix/sysv/linux/pwritev2.c @@ -28,7 +28,7 @@ pwritev2 (int fd, const struct iovec *vector, int count, off_t offset, # ifdef __NR_pwritev2 ssize_t result = SYSCALL_CANCEL (pwritev2, fd, vector, count, LO_HI_LONG (offset), flags); - if (result >= 0) + if (result >= 0 || errno != ENOSYS) return result; # endif /* Trying to emulate the pwritev2 syscall flags is troublesome: diff --git a/sysdeps/unix/sysv/linux/pwritev64v2.c b/sysdeps/unix/sysv/linux/pwritev64v2.c index 42da321149..17ea905aa6 100644 --- a/sysdeps/unix/sysv/linux/pwritev64v2.c +++ b/sysdeps/unix/sysv/linux/pwritev64v2.c @@ -30,7 +30,7 @@ pwritev64v2 (int fd, const struct iovec *vector, int count, off64_t offset, #ifdef __NR_pwritev64v2 ssize_t result = SYSCALL_CANCEL (pwritev64v2, fd, vector, count, LO_HI_LONG (offset), flags); - if (result >= 0) + if (result >= 0 || errno != ENOSYS) return result; #endif /* Trying to emulate the pwritev2 syscall flags is troublesome: diff --git a/sysdeps/unix/sysv/linux/riscv/clone.S b/sysdeps/unix/sysv/linux/riscv/clone.S index 392af72b55..1c5b12566e 100644 --- a/sysdeps/unix/sysv/linux/riscv/clone.S +++ b/sysdeps/unix/sysv/linux/riscv/clone.S @@ -69,6 +69,11 @@ L (error): ENTRY (__thread_start) L (thread_start): + /* Terminate call stack by noting ra is undefined. Use a dummy + .cfi_label to force starting the FDE. */ + .cfi_label .Ldummy + cfi_undefined (ra) + /* Restore the arg for user's function. */ REG_L a1,0(sp) /* Function pointer. */ REG_L a0,SZREG(sp) /* Argument pointer. */ diff --git a/sysdeps/unix/sysv/linux/riscv/flush-icache.c b/sysdeps/unix/sysv/linux/riscv/flush-icache.c index d612ef4c6c..0b2042620b 100644 --- a/sysdeps/unix/sysv/linux/riscv/flush-icache.c +++ b/sysdeps/unix/sysv/linux/riscv/flush-icache.c @@ -21,7 +21,11 @@ #include #include #include -#include +#if __has_include__ () +# include +#else +# include +#endif typedef int (*func_type) (void *, void *, unsigned long int); diff --git a/sysdeps/unix/sysv/linux/riscv/kernel-features.h b/sysdeps/unix/sysv/linux/riscv/kernel-features.h index 37f4d99a92..d21c824624 100644 --- a/sysdeps/unix/sysv/linux/riscv/kernel-features.h +++ b/sysdeps/unix/sysv/linux/riscv/kernel-features.h @@ -21,3 +21,8 @@ #undef __ASSUME_CLONE_DEFAULT #define __ASSUME_CLONE_BACKWARDS 1 + +/* No support for PI mutexes or robust futexes before 4.20. */ +#if __LINUX_KERNEL_VERSION < 0x041400 +# undef __ASSUME_SET_ROBUST_LIST +#endif diff --git a/sysdeps/unix/sysv/linux/s390/force-elision.h b/sysdeps/unix/sysv/linux/s390/force-elision.h index d8a1b9972f..71f32367dd 100644 --- a/sysdeps/unix/sysv/linux/s390/force-elision.h +++ b/sysdeps/unix/sysv/linux/s390/force-elision.h @@ -18,9 +18,45 @@ /* Automatically enable elision for existing user lock kinds. */ #define FORCE_ELISION(m, s) \ - if (__pthread_force_elision \ - && (m->__data.__kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0) \ + if (__pthread_force_elision) \ { \ - mutex->__data.__kind |= PTHREAD_MUTEX_ELISION_NP; \ - s; \ + /* See concurrency notes regarding __kind in \ + struct __pthread_mutex_s in \ + sysdeps/nptl/bits/thread-shared-types.h. \ + \ + There are the following cases for the kind of a mutex \ + (The mask PTHREAD_MUTEX_ELISION_FLAGS_NP covers the flags \ + PTHREAD_MUTEX_ELISION_NP and PTHREAD_MUTEX_NO_ELISION_NP where \ + only one of both flags can be set): \ + - both flags are not set: \ + This is the first lock operation for this mutex. Enable \ + elision as it is not enabled so far. \ + Note: It can happen that multiple threads are calling e.g. \ + pthread_mutex_lock at the same time as the first lock \ + operation for this mutex. Then elision is enabled for this \ + mutex by multiple threads. Storing with relaxed MO is enough \ + as all threads will store the same new value for the kind of \ + the mutex. But we have to ensure that we always use the \ + elision path regardless if this thread has enabled elision or \ + another one. \ + \ + - PTHREAD_MUTEX_ELISION_NP flag is set: \ + Elision was already enabled for this mutex by a previous lock \ + operation. See case above. Just use the elision path. \ + \ + - PTHREAD_MUTEX_NO_ELISION_NP flag is set: \ + Elision was explicitly disabled by pthread_mutexattr_settype. \ + Do not use the elision path. \ + Note: The flag PTHREAD_MUTEX_NO_ELISION_NP will never be \ + changed after mutex initialization. */ \ + int mutex_kind = atomic_load_relaxed (&((m)->__data.__kind)); \ + if ((mutex_kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0) \ + { \ + mutex_kind |= PTHREAD_MUTEX_ELISION_NP; \ + atomic_store_relaxed (&((m)->__data.__kind), mutex_kind); \ + } \ + if ((mutex_kind & PTHREAD_MUTEX_ELISION_NP) != 0) \ + { \ + s; \ + } \ } diff --git a/sysdeps/unix/sysv/linux/sh/kernel_sigaction.h b/sysdeps/unix/sysv/linux/sh/kernel_sigaction.h index 7ebcd08d62..c8dc77a02b 100644 --- a/sysdeps/unix/sysv/linux/sh/kernel_sigaction.h +++ b/sysdeps/unix/sysv/linux/sh/kernel_sigaction.h @@ -1,8 +1,9 @@ /* SH uses the generic Linux UAPI but defines SA_RESTORER. */ #define SA_RESTORER 0x04000000 -#include #define SET_SA_RESTORER(kact, act) \ (kact)->sa_restorer = (act)->sa_restorer #define RESET_SA_RESTORER(act, kact) \ (act)->sa_restorer = (kact)->sa_restorer + +#include diff --git a/sysdeps/unix/sysv/linux/sparc/bits/siginfo-arch.h b/sysdeps/unix/sysv/linux/sparc/bits/siginfo-arch.h index 9f79715ebe..4dd35237f6 100644 --- a/sysdeps/unix/sysv/linux/sparc/bits/siginfo-arch.h +++ b/sysdeps/unix/sysv/linux/sparc/bits/siginfo-arch.h @@ -2,7 +2,12 @@ #ifndef _BITS_SIGINFO_ARCH_H #define _BITS_SIGINFO_ARCH_H 1 -#define __SI_BAND_TYPE int +/* The kernel uses int instead of long int (as in POSIX). In 32-bit + mode, we can still use long int, but in 64-bit mode, we need to + deviate from POSIX. */ +#if __WORDSIZE == 64 +# define __SI_BAND_TYPE int +#endif #define __SI_SIGFAULT_ADDL \ int _si_trapno; diff --git a/sysdeps/unix/sysv/linux/sparc/kernel_sigaction.h b/sysdeps/unix/sysv/linux/sparc/kernel_sigaction.h index bee7e9cd03..eb4a522453 100644 --- a/sysdeps/unix/sysv/linux/sparc/kernel_sigaction.h +++ b/sysdeps/unix/sysv/linux/sparc/kernel_sigaction.h @@ -1,10 +1,5 @@ /* SPARC 'struct __new_sigaction' is similar to generic Linux UAPI with a sa_restorer field, even though function is passed as an argument to rt_sigaction syscall. */ -#define SA_RESTORER 0x04000000 +#define HAS_SA_RESTORER 1 #include - -#define SET_SA_RESTORER(kact, act) \ - (kact)->sa_restorer = NULL -#define RESET_SA_RESTORER(act, kact) \ - (act)->sa_restorer = (kact)->sa_restorer diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/Makefile b/sysdeps/unix/sysv/linux/sparc/sparc64/Makefile index 715af3df7b..218c246f16 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc64/Makefile +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/Makefile @@ -7,3 +7,8 @@ LD += -melf64_sparc ifeq ($(subdir),stdlib) sysdep_routines += __start_context endif + +ifeq ($(subdir),conform) +# For bug 23821 (incorrect type of si_band). +conformtest-xfail-conds += sparc64-linux +endif diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c index cf0213ece5..85239cedbf 100644 --- a/sysdeps/unix/sysv/linux/spawni.c +++ b/sysdeps/unix/sysv/linux/spawni.c @@ -101,7 +101,7 @@ maybe_script_execute (struct posix_spawn_args *args) ptrdiff_t argc = args->argc; /* Construct an argument list for the shell. */ - char *new_argv[argc + 1]; + char *new_argv[argc + 2]; new_argv[0] = (char *) _PATH_BSHELL; new_argv[1] = (char *) args->file; if (argc > 1) diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list index 5306d538e6..f88001c9c3 100644 --- a/sysdeps/unix/sysv/linux/syscall-names.list +++ b/sysdeps/unix/sysv/linux/syscall-names.list @@ -22,8 +22,8 @@ # names are only used if the installed kernel headers also provide # them. -# The list of system calls is current as of Linux 4.17. -kernel 4.17 +# The list of system calls is current as of Linux 4.19. +kernel 4.19 FAST_atomic_update FAST_cmpxchg @@ -186,6 +186,7 @@ inotify_rm_watch io_cancel io_destroy io_getevents +io_pgetevents io_setup io_submit ioctl @@ -431,6 +432,7 @@ renameat2 request_key restart_syscall rmdir +rseq rt_sigaction rt_sigpending rt_sigprocmask diff --git a/sysdeps/unix/sysv/linux/tst-readdir64-compat.c b/sysdeps/unix/sysv/linux/tst-readdir64-compat.c new file mode 100644 index 0000000000..cb78bc9be4 --- /dev/null +++ b/sysdeps/unix/sysv/linux/tst-readdir64-compat.c @@ -0,0 +1,115 @@ +/* Test readdir64 compatibility symbol. + 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 + +/* Copied from . */ +struct __old_dirent64 + { + __ino_t d_ino; + __off64_t d_off; + unsigned short int d_reclen; + unsigned char d_type; + char d_name[256]; + }; + +typedef struct __old_dirent64 *(*compat_readdir64_type) (DIR *); + +#if TEST_COMPAT (libc, GLIBC_2_1, GLIBC_2_2) +struct __old_dirent64 *compat_readdir64 (DIR *); +compat_symbol_reference (libc, compat_readdir64, readdir64, GLIBC_2_1); +#endif + +static int +do_test (void) +{ +#if TEST_COMPAT (libc, GLIBC_2_1, GLIBC_2_2) + + /* Directory stream using the non-compat readdir64 symbol. The test + checks against this. */ + DIR *dir_reference = opendir ("."); + TEST_VERIFY_EXIT (dir_reference != NULL); + DIR *dir_test = opendir ("."); + TEST_VERIFY_EXIT (dir_test != NULL); + + /* This loop assumes that the enumeration order is consistent for + two different handles. Nothing should write to the current + directory (in the source tree) while this test runs, so there + should not be any difference due to races. */ + size_t count = 0; + while (true) + { + errno = 0; + struct dirent64 *entry_reference = readdir64 (dir_reference); + if (entry_reference == NULL && errno != 0) + FAIL_EXIT1 ("readdir64 entry %zu: %m\n", count); + struct __old_dirent64 *entry_test = compat_readdir64 (dir_test); + if (entry_reference == NULL) + { + if (errno == EOVERFLOW) + { + TEST_VERIFY (entry_reference->d_ino + != (__ino_t) entry_reference->d_ino); + printf ("info: inode number overflow at entry %zu\n", count); + break; + } + if (errno != 0) + FAIL_EXIT1 ("compat readdir64 entry %zu: %m\n", count); + } + + /* Check that both streams end at the same time. */ + if (entry_reference == NULL) + { + TEST_VERIFY (entry_test == NULL); + break; + } + else + TEST_VERIFY_EXIT (entry_test != NULL); + + /* d_off is never zero because it is the offset of the next + entry (not the current entry). */ + TEST_VERIFY (entry_reference->d_off > 0); + + /* Check that the entries are the same. */ + TEST_COMPARE_BLOB (entry_reference->d_name, + strlen (entry_reference->d_name), + entry_test->d_name, strlen (entry_test->d_name)); + TEST_COMPARE (entry_reference->d_ino, entry_test->d_ino); + TEST_COMPARE (entry_reference->d_off, entry_test->d_off); + TEST_COMPARE (entry_reference->d_type, entry_test->d_type); + TEST_COMPARE (entry_reference->d_reclen, entry_test->d_reclen); + + ++count; + } + printf ("info: %zu directory entries found\n", count); + TEST_VERIFY (count >= 3); /* ".", "..", and some source files. */ + + TEST_COMPARE (closedir (dir_test), 0); + TEST_COMPARE (closedir (dir_reference), 0); +#endif + return 0; +} + +#include diff --git a/sysdeps/unix/sysv/linux/x86/force-elision.h b/sysdeps/unix/sysv/linux/x86/force-elision.h index dd659c908f..61282d6678 100644 --- a/sysdeps/unix/sysv/linux/x86/force-elision.h +++ b/sysdeps/unix/sysv/linux/x86/force-elision.h @@ -18,9 +18,45 @@ /* Automatically enable elision for existing user lock kinds. */ #define FORCE_ELISION(m, s) \ - if (__pthread_force_elision \ - && (m->__data.__kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0) \ + if (__pthread_force_elision) \ { \ - mutex->__data.__kind |= PTHREAD_MUTEX_ELISION_NP; \ - s; \ + /* See concurrency notes regarding __kind in \ + struct __pthread_mutex_s in \ + sysdeps/nptl/bits/thread-shared-types.h. \ + \ + There are the following cases for the kind of a mutex \ + (The mask PTHREAD_MUTEX_ELISION_FLAGS_NP covers the flags \ + PTHREAD_MUTEX_ELISION_NP and PTHREAD_MUTEX_NO_ELISION_NP where \ + only one of both flags can be set): \ + - both flags are not set: \ + This is the first lock operation for this mutex. Enable \ + elision as it is not enabled so far. \ + Note: It can happen that multiple threads are calling e.g. \ + pthread_mutex_lock at the same time as the first lock \ + operation for this mutex. Then elision is enabled for this \ + mutex by multiple threads. Storing with relaxed MO is enough \ + as all threads will store the same new value for the kind of \ + the mutex. But we have to ensure that we always use the \ + elision path regardless if this thread has enabled elision or \ + another one. \ + \ + - PTHREAD_MUTEX_ELISION_NP flag is set: \ + Elision was already enabled for this mutex by a previous lock \ + operation. See case above. Just use the elision path. \ + \ + - PTHREAD_MUTEX_NO_ELISION_NP flag is set: \ + Elision was explicitly disabled by pthread_mutexattr_settype. \ + Do not use the elision path. \ + Note: The flag PTHREAD_MUTEX_NO_ELISION_NP will never be \ + changed after mutex initialization. */ \ + int mutex_kind = atomic_load_relaxed (&((m)->__data.__kind)); \ + if ((mutex_kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0) \ + { \ + mutex_kind |= PTHREAD_MUTEX_ELISION_NP; \ + atomic_store_relaxed (&((m)->__data.__kind), mutex_kind); \ + } \ + if ((mutex_kind & PTHREAD_MUTEX_ELISION_NP) != 0) \ + { \ + s; \ + } \ } diff --git a/sysdeps/unix/sysv/linux/x86_64/sigaction.c b/sysdeps/unix/sysv/linux/x86_64/sigaction.c index 4e6d9cc32e..9aa2c7f860 100644 --- a/sysdeps/unix/sysv/linux/x86_64/sigaction.c +++ b/sysdeps/unix/sysv/linux/x86_64/sigaction.c @@ -18,7 +18,6 @@ #include #define SA_RESTORER 0x04000000 -#include extern void restore_rt (void) asm ("__restore_rt") attribute_hidden; @@ -29,6 +28,8 @@ extern void restore_rt (void) asm ("__restore_rt") attribute_hidden; #define RESET_SA_RESTORER(act, kact) \ (act)->sa_restorer = (kact)->sa_restorer +#include + #include /* NOTE: Please think twice before making any changes to the bits of diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c index ea0b64fdb9..4695ac80d4 100644 --- a/sysdeps/x86/cpu-features.c +++ b/sysdeps/x86/cpu-features.c @@ -316,7 +316,13 @@ init_cpu_features (struct cpu_features *cpu_features) | bit_arch_Fast_Unaligned_Copy | bit_arch_Prefer_PMINUB_for_stringop); break; + } + /* Disable TSX on some Haswell processors to avoid TSX on kernels that + weren't updated with the latest microcode package (which disables + broken feature by default). */ + switch (model) + { case 0x3f: /* Xeon E7 v3 with stepping >= 4 has working TSX. */ if (stepping >= 4) diff --git a/sysdeps/x86/dl-prop.h b/sysdeps/x86/dl-prop.h index 26c3131ac5..9ab890d12b 100644 --- a/sysdeps/x86/dl-prop.h +++ b/sysdeps/x86/dl-prop.h @@ -49,6 +49,10 @@ _dl_process_cet_property_note (struct link_map *l, const ElfW(Addr) align) { #if CET_ENABLED + /* Skip if we have seen a NT_GNU_PROPERTY_TYPE_0 note before. */ + if (l->l_cet != lc_unknown) + return; + /* The NT_GNU_PROPERTY_TYPE_0 note must be aliged to 4 bytes in 32-bit objects and to 8 bytes in 64-bit objects. Skip notes with incorrect alignment. */ @@ -57,6 +61,9 @@ _dl_process_cet_property_note (struct link_map *l, const ElfW(Addr) start = (ElfW(Addr)) note; + unsigned int feature_1 = 0; + unsigned int last_type = 0; + while ((ElfW(Addr)) (note + 1) - start < size) { /* Find the NT_GNU_PROPERTY_TYPE_0 note. */ @@ -64,10 +71,18 @@ _dl_process_cet_property_note (struct link_map *l, && note->n_type == NT_GNU_PROPERTY_TYPE_0 && memcmp (note + 1, "GNU", 4) == 0) { + /* Stop if we see more than one GNU property note which may + be generated by the older linker. */ + if (l->l_cet != lc_unknown) + return; + + /* Check CET status now. */ + l->l_cet = lc_none; + /* Check for invalid property. */ if (note->n_descsz < 8 || (note->n_descsz % sizeof (ElfW(Addr))) != 0) - break; + return; /* Start and end of property array. */ unsigned char *ptr = (unsigned char *) (note + 1) + 4; @@ -78,9 +93,15 @@ _dl_process_cet_property_note (struct link_map *l, unsigned int type = *(unsigned int *) ptr; unsigned int datasz = *(unsigned int *) (ptr + 4); + /* Property type must be in ascending order. */ + if (type < last_type) + return; + ptr += 8; if ((ptr + datasz) > ptr_end) - break; + return; + + last_type = type; if (type == GNU_PROPERTY_X86_FEATURE_1_AND) { @@ -89,14 +110,18 @@ _dl_process_cet_property_note (struct link_map *l, we stop the search regardless if its size is correct or not. There is no point to continue if this note is ill-formed. */ - if (datasz == 4) - { - unsigned int feature_1 = *(unsigned int *) ptr; - if ((feature_1 & GNU_PROPERTY_X86_FEATURE_1_IBT)) - l->l_cet |= lc_ibt; - if ((feature_1 & GNU_PROPERTY_X86_FEATURE_1_SHSTK)) - l->l_cet |= lc_shstk; - } + if (datasz != 4) + return; + + feature_1 = *(unsigned int *) ptr; + + /* Keep searching for the next GNU property note + generated by the older linker. */ + break; + } + else if (type > GNU_PROPERTY_X86_FEATURE_1_AND) + { + /* Stop since property type is in ascending order. */ return; } @@ -112,6 +137,12 @@ _dl_process_cet_property_note (struct link_map *l, + ELF_NOTE_NEXT_OFFSET (note->n_namesz, note->n_descsz, align)); } + + /* We get here only if there is one or no GNU property note. */ + if ((feature_1 & GNU_PROPERTY_X86_FEATURE_1_IBT)) + l->l_cet |= lc_ibt; + if ((feature_1 & GNU_PROPERTY_X86_FEATURE_1_SHSTK)) + l->l_cet |= lc_shstk; #endif } diff --git a/sysdeps/x86/link_map.h b/sysdeps/x86/link_map.h index ef1206a9d2..9367ed0889 100644 --- a/sysdeps/x86/link_map.h +++ b/sysdeps/x86/link_map.h @@ -19,8 +19,9 @@ /* If this object is enabled with CET. */ enum { - lc_none = 0, /* Not enabled with CET. */ - lc_ibt = 1 << 0, /* Enabled with IBT. */ - lc_shstk = 1 << 1, /* Enabled with STSHK. */ + lc_unknown = 0, /* Unknown CET status. */ + lc_none = 1 << 0, /* Not enabled with CET. */ + lc_ibt = 1 << 1, /* Enabled with IBT. */ + lc_shstk = 1 << 2, /* Enabled with STSHK. */ lc_ibt_and_shstk = lc_ibt | lc_shstk /* Enabled with both. */ - } l_cet:2; + } l_cet:3; diff --git a/sysdeps/x86_64/dl-irel.h b/sysdeps/x86_64/dl-irel.h index 6ecc50fb42..33f100d8b1 100644 --- a/sysdeps/x86_64/dl-irel.h +++ b/sysdeps/x86_64/dl-irel.h @@ -45,7 +45,7 @@ elf_irela (const ElfW(Rela) *reloc) *reloc_addr = value; } else - __libc_fatal ("unexpected reloc type in static binary"); + __libc_fatal ("Unexpected reloc type in static binary.\n"); } #endif /* dl-irel.h */ diff --git a/sysdeps/x86_64/memchr.S b/sysdeps/x86_64/memchr.S index feef5d4f24..cb320257a2 100644 --- a/sysdeps/x86_64/memchr.S +++ b/sysdeps/x86_64/memchr.S @@ -34,12 +34,16 @@ ENTRY(MEMCHR) mov %edi, %ecx #ifdef USE_AS_WMEMCHR - test %rdx, %rdx + test %RDX_LP, %RDX_LP jz L(return_null) - shl $2, %rdx + shl $2, %RDX_LP #else +# ifdef __ILP32__ + /* Clear the upper 32 bits. */ + movl %edx, %edx +# endif punpcklbw %xmm1, %xmm1 - test %rdx, %rdx + test %RDX_LP, %RDX_LP jz L(return_null) punpcklbw %xmm1, %xmm1 #endif diff --git a/sysdeps/x86_64/memcmp.S b/sysdeps/x86_64/memcmp.S index bcb4a2e88d..45918d375a 100644 --- a/sysdeps/x86_64/memcmp.S +++ b/sysdeps/x86_64/memcmp.S @@ -21,14 +21,18 @@ .text ENTRY (memcmp) - test %rdx, %rdx +#ifdef __ILP32__ + /* Clear the upper 32 bits. */ + movl %edx, %edx +#endif + test %RDX_LP, %RDX_LP jz L(finz) cmpq $1, %rdx - jle L(finr1b) + jbe L(finr1b) subq %rdi, %rsi movq %rdx, %r10 cmpq $32, %r10 - jge L(gt32) + jae L(gt32) /* Handle small chunks and last block of less than 32 bytes. */ L(small): testq $1, %r10 @@ -156,7 +160,7 @@ L(A32): movq %r11, %r10 andq $-32, %r10 cmpq %r10, %rdi - jge L(mt16) + jae L(mt16) /* Pre-unroll to be ready for unrolled 64B loop. */ testq $32, %rdi jz L(A64) @@ -178,7 +182,7 @@ L(A64): movq %r11, %r10 andq $-64, %r10 cmpq %r10, %rdi - jge L(mt32) + jae L(mt32) L(A64main): movdqu (%rdi,%rsi), %xmm0 @@ -216,7 +220,7 @@ L(mt32): movq %r11, %r10 andq $-32, %r10 cmpq %r10, %rdi - jge L(mt16) + jae L(mt16) L(A32main): movdqu (%rdi,%rsi), %xmm0 @@ -254,7 +258,7 @@ L(ATR): movq %r11, %r10 andq $-32, %r10 cmpq %r10, %rdi - jge L(mt16) + jae L(mt16) testq $16, %rdi jz L(ATR32) @@ -325,7 +329,7 @@ L(ATR64main): movq %r11, %r10 andq $-32, %r10 cmpq %r10, %rdi - jge L(mt16) + jae L(mt16) L(ATR32res): movdqa (%rdi,%rsi), %xmm0 diff --git a/sysdeps/x86_64/memrchr.S b/sysdeps/x86_64/memrchr.S index b8e3fa1d87..dc82f8f73d 100644 --- a/sysdeps/x86_64/memrchr.S +++ b/sysdeps/x86_64/memrchr.S @@ -24,13 +24,13 @@ ENTRY (__memrchr) movd %esi, %xmm1 - sub $16, %rdx + sub $16, %RDX_LP jbe L(length_less16) punpcklbw %xmm1, %xmm1 punpcklbw %xmm1, %xmm1 - add %rdx, %rdi + add %RDX_LP, %RDI_LP pshufd $0, %xmm1, %xmm1 movdqu (%rdi), %xmm0 diff --git a/sysdeps/x86_64/multiarch/memchr-avx2.S b/sysdeps/x86_64/multiarch/memchr-avx2.S index 5f5e772554..c81da19bf0 100644 --- a/sysdeps/x86_64/multiarch/memchr-avx2.S +++ b/sysdeps/x86_64/multiarch/memchr-avx2.S @@ -40,16 +40,20 @@ ENTRY (MEMCHR) # ifndef USE_AS_RAWMEMCHR /* Check for zero length. */ - testq %rdx, %rdx + test %RDX_LP, %RDX_LP jz L(null) # endif movl %edi, %ecx /* Broadcast CHAR to YMM0. */ vmovd %esi, %xmm0 # ifdef USE_AS_WMEMCHR - shl $2, %rdx + shl $2, %RDX_LP vpbroadcastd %xmm0, %ymm0 # else +# ifdef __ILP32__ + /* Clear the upper 32 bits. */ + movl %edx, %edx +# endif vpbroadcastb %xmm0, %ymm0 # endif /* Check if we may cross page boundary with one vector load. */ diff --git a/sysdeps/x86_64/multiarch/memcmp-avx2-movbe.S b/sysdeps/x86_64/multiarch/memcmp-avx2-movbe.S index 30f764c393..e3a35b899e 100644 --- a/sysdeps/x86_64/multiarch/memcmp-avx2-movbe.S +++ b/sysdeps/x86_64/multiarch/memcmp-avx2-movbe.S @@ -58,9 +58,12 @@ .section .text.avx,"ax",@progbits ENTRY (MEMCMP) # ifdef USE_AS_WMEMCMP - shl $2, %rdx + shl $2, %RDX_LP +# elif defined __ILP32__ + /* Clear the upper 32 bits. */ + movl %edx, %edx # endif - cmpq $VEC_SIZE, %rdx + cmp $VEC_SIZE, %RDX_LP jb L(less_vec) /* From VEC to 2 * VEC. No branch when size == VEC_SIZE. */ diff --git a/sysdeps/x86_64/multiarch/memcmp-sse4.S b/sysdeps/x86_64/multiarch/memcmp-sse4.S index 8e164f2cb6..302900f5b8 100644 --- a/sysdeps/x86_64/multiarch/memcmp-sse4.S +++ b/sysdeps/x86_64/multiarch/memcmp-sse4.S @@ -42,13 +42,16 @@ .section .text.sse4.1,"ax",@progbits ENTRY (MEMCMP) # ifdef USE_AS_WMEMCMP - shl $2, %rdx + shl $2, %RDX_LP +# elif defined __ILP32__ + /* Clear the upper 32 bits. */ + mov %edx, %edx # endif pxor %xmm0, %xmm0 - cmp $79, %rdx + cmp $79, %RDX_LP ja L(79bytesormore) # ifndef USE_AS_WMEMCMP - cmp $1, %rdx + cmp $1, %RDX_LP je L(firstbyte) # endif add %rdx, %rsi diff --git a/sysdeps/x86_64/multiarch/memcmp-ssse3.S b/sysdeps/x86_64/multiarch/memcmp-ssse3.S index 6f76c64123..69d030fc00 100644 --- a/sysdeps/x86_64/multiarch/memcmp-ssse3.S +++ b/sysdeps/x86_64/multiarch/memcmp-ssse3.S @@ -33,9 +33,12 @@ atom_text_section ENTRY (MEMCMP) # ifdef USE_AS_WMEMCMP - shl $2, %rdx - test %rdx, %rdx + shl $2, %RDX_LP + test %RDX_LP, %RDX_LP jz L(equal) +# elif defined __ILP32__ + /* Clear the upper 32 bits. */ + mov %edx, %edx # endif mov %rdx, %rcx mov %rdi, %rdx diff --git a/sysdeps/x86_64/multiarch/memcpy-ssse3-back.S b/sysdeps/x86_64/multiarch/memcpy-ssse3-back.S index 3cd1123326..568eebd3ae 100644 --- a/sysdeps/x86_64/multiarch/memcpy-ssse3-back.S +++ b/sysdeps/x86_64/multiarch/memcpy-ssse3-back.S @@ -45,28 +45,33 @@ .section .text.ssse3,"ax",@progbits #if !defined USE_AS_MEMPCPY && !defined USE_AS_MEMMOVE ENTRY (MEMPCPY_CHK) - cmpq %rdx, %rcx + cmp %RDX_LP, %RCX_LP jb HIDDEN_JUMPTARGET (__chk_fail) END (MEMPCPY_CHK) ENTRY (MEMPCPY) - movq %rdi, %rax - addq %rdx, %rax + mov %RDI_LP, %RAX_LP + add %RDX_LP, %RAX_LP jmp L(start) END (MEMPCPY) #endif #if !defined USE_AS_BCOPY ENTRY (MEMCPY_CHK) - cmpq %rdx, %rcx + cmp %RDX_LP, %RCX_LP jb HIDDEN_JUMPTARGET (__chk_fail) END (MEMCPY_CHK) #endif ENTRY (MEMCPY) - mov %rdi, %rax + mov %RDI_LP, %RAX_LP #ifdef USE_AS_MEMPCPY - add %rdx, %rax + add %RDX_LP, %RAX_LP +#endif + +#ifdef __ILP32__ + /* Clear the upper 32 bits. */ + mov %edx, %edx #endif #ifdef USE_AS_MEMMOVE diff --git a/sysdeps/x86_64/multiarch/memcpy-ssse3.S b/sysdeps/x86_64/multiarch/memcpy-ssse3.S index 0240bfa309..0bd5ee999a 100644 --- a/sysdeps/x86_64/multiarch/memcpy-ssse3.S +++ b/sysdeps/x86_64/multiarch/memcpy-ssse3.S @@ -45,28 +45,33 @@ .section .text.ssse3,"ax",@progbits #if !defined USE_AS_MEMPCPY && !defined USE_AS_MEMMOVE ENTRY (MEMPCPY_CHK) - cmpq %rdx, %rcx + cmp %RDX_LP, %RCX_LP jb HIDDEN_JUMPTARGET (__chk_fail) END (MEMPCPY_CHK) ENTRY (MEMPCPY) - movq %rdi, %rax - addq %rdx, %rax + mov %RDI_LP, %RAX_LP + add %RDX_LP, %RAX_LP jmp L(start) END (MEMPCPY) #endif #if !defined USE_AS_BCOPY ENTRY (MEMCPY_CHK) - cmpq %rdx, %rcx + cmp %RDX_LP, %RCX_LP jb HIDDEN_JUMPTARGET (__chk_fail) END (MEMCPY_CHK) #endif ENTRY (MEMCPY) - mov %rdi, %rax + mov %RDI_LP, %RAX_LP #ifdef USE_AS_MEMPCPY - add %rdx, %rax + add %RDX_LP, %RAX_LP +#endif + +#ifdef __ILP32__ + /* Clear the upper 32 bits. */ + mov %edx, %edx #endif #ifdef USE_AS_MEMMOVE diff --git a/sysdeps/x86_64/multiarch/memmove-avx512-no-vzeroupper.S b/sysdeps/x86_64/multiarch/memmove-avx512-no-vzeroupper.S index effc3ac2de..6ca2bbc91a 100644 --- a/sysdeps/x86_64/multiarch/memmove-avx512-no-vzeroupper.S +++ b/sysdeps/x86_64/multiarch/memmove-avx512-no-vzeroupper.S @@ -24,27 +24,31 @@ .section .text.avx512,"ax",@progbits ENTRY (__mempcpy_chk_avx512_no_vzeroupper) - cmpq %rdx, %rcx + cmp %RDX_LP, %RCX_LP jb HIDDEN_JUMPTARGET (__chk_fail) END (__mempcpy_chk_avx512_no_vzeroupper) ENTRY (__mempcpy_avx512_no_vzeroupper) - movq %rdi, %rax - addq %rdx, %rax + mov %RDI_LP, %RAX_LP + add %RDX_LP, %RAX_LP jmp L(start) END (__mempcpy_avx512_no_vzeroupper) ENTRY (__memmove_chk_avx512_no_vzeroupper) - cmpq %rdx, %rcx + cmp %RDX_LP, %RCX_LP jb HIDDEN_JUMPTARGET (__chk_fail) END (__memmove_chk_avx512_no_vzeroupper) ENTRY (__memmove_avx512_no_vzeroupper) - mov %rdi, %rax + mov %RDI_LP, %RAX_LP # ifdef USE_AS_MEMPCPY - add %rdx, %rax + add %RDX_LP, %RAX_LP # endif L(start): +# ifdef __ILP32__ + /* Clear the upper 32 bits. */ + mov %edx, %edx +# endif lea (%rsi, %rdx), %rcx lea (%rdi, %rdx), %r9 cmp $512, %rdx diff --git a/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S b/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S index e2ede45e9f..9bab1147d5 100644 --- a/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S +++ b/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S @@ -106,20 +106,20 @@ .section SECTION(.text),"ax",@progbits #if defined SHARED && IS_IN (libc) ENTRY (MEMMOVE_CHK_SYMBOL (__mempcpy_chk, unaligned)) - cmpq %rdx, %rcx + cmp %RDX_LP, %RCX_LP jb HIDDEN_JUMPTARGET (__chk_fail) END (MEMMOVE_CHK_SYMBOL (__mempcpy_chk, unaligned)) #endif ENTRY (MEMPCPY_SYMBOL (__mempcpy, unaligned)) - movq %rdi, %rax - addq %rdx, %rax + mov %RDI_LP, %RAX_LP + add %RDX_LP, %RAX_LP jmp L(start) END (MEMPCPY_SYMBOL (__mempcpy, unaligned)) #if defined SHARED && IS_IN (libc) ENTRY (MEMMOVE_CHK_SYMBOL (__memmove_chk, unaligned)) - cmpq %rdx, %rcx + cmp %RDX_LP, %RCX_LP jb HIDDEN_JUMPTARGET (__chk_fail) END (MEMMOVE_CHK_SYMBOL (__memmove_chk, unaligned)) #endif @@ -127,9 +127,13 @@ END (MEMMOVE_CHK_SYMBOL (__memmove_chk, unaligned)) ENTRY (MEMMOVE_SYMBOL (__memmove, unaligned)) movq %rdi, %rax L(start): - cmpq $VEC_SIZE, %rdx +# ifdef __ILP32__ + /* Clear the upper 32 bits. */ + movl %edx, %edx +# endif + cmp $VEC_SIZE, %RDX_LP jb L(less_vec) - cmpq $(VEC_SIZE * 2), %rdx + cmp $(VEC_SIZE * 2), %RDX_LP ja L(more_2x_vec) #if !defined USE_MULTIARCH || !IS_IN (libc) L(last_2x_vec): @@ -149,38 +153,38 @@ END (MEMMOVE_SYMBOL (__memmove, unaligned)) # if VEC_SIZE == 16 ENTRY (__mempcpy_chk_erms) - cmpq %rdx, %rcx + cmp %RDX_LP, %RCX_LP jb HIDDEN_JUMPTARGET (__chk_fail) END (__mempcpy_chk_erms) /* Only used to measure performance of REP MOVSB. */ ENTRY (__mempcpy_erms) - movq %rdi, %rax + mov %RDI_LP, %RAX_LP /* Skip zero length. */ - testq %rdx, %rdx + test %RDX_LP, %RDX_LP jz 2f - addq %rdx, %rax + add %RDX_LP, %RAX_LP jmp L(start_movsb) END (__mempcpy_erms) ENTRY (__memmove_chk_erms) - cmpq %rdx, %rcx + cmp %RDX_LP, %RCX_LP jb HIDDEN_JUMPTARGET (__chk_fail) END (__memmove_chk_erms) ENTRY (__memmove_erms) movq %rdi, %rax /* Skip zero length. */ - testq %rdx, %rdx + test %RDX_LP, %RDX_LP jz 2f L(start_movsb): - movq %rdx, %rcx - cmpq %rsi, %rdi + mov %RDX_LP, %RCX_LP + cmp %RSI_LP, %RDI_LP jb 1f /* Source == destination is less common. */ je 2f - leaq (%rsi,%rcx), %rdx - cmpq %rdx, %rdi + lea (%rsi,%rcx), %RDX_LP + cmp %RDX_LP, %RDI_LP jb L(movsb_backward) 1: rep movsb @@ -200,20 +204,20 @@ strong_alias (__memmove_chk_erms, __memcpy_chk_erms) # ifdef SHARED ENTRY (MEMMOVE_CHK_SYMBOL (__mempcpy_chk, unaligned_erms)) - cmpq %rdx, %rcx + cmp %RDX_LP, %RCX_LP jb HIDDEN_JUMPTARGET (__chk_fail) END (MEMMOVE_CHK_SYMBOL (__mempcpy_chk, unaligned_erms)) # endif ENTRY (MEMMOVE_SYMBOL (__mempcpy, unaligned_erms)) - movq %rdi, %rax - addq %rdx, %rax + mov %RDI_LP, %RAX_LP + add %RDX_LP, %RAX_LP jmp L(start_erms) END (MEMMOVE_SYMBOL (__mempcpy, unaligned_erms)) # ifdef SHARED ENTRY (MEMMOVE_CHK_SYMBOL (__memmove_chk, unaligned_erms)) - cmpq %rdx, %rcx + cmp %RDX_LP, %RCX_LP jb HIDDEN_JUMPTARGET (__chk_fail) END (MEMMOVE_CHK_SYMBOL (__memmove_chk, unaligned_erms)) # endif @@ -221,9 +225,13 @@ END (MEMMOVE_CHK_SYMBOL (__memmove_chk, unaligned_erms)) ENTRY (MEMMOVE_SYMBOL (__memmove, unaligned_erms)) movq %rdi, %rax L(start_erms): - cmpq $VEC_SIZE, %rdx +# ifdef __ILP32__ + /* Clear the upper 32 bits. */ + movl %edx, %edx +# endif + cmp $VEC_SIZE, %RDX_LP jb L(less_vec) - cmpq $(VEC_SIZE * 2), %rdx + cmp $(VEC_SIZE * 2), %RDX_LP ja L(movsb_more_2x_vec) L(last_2x_vec): /* From VEC and to 2 * VEC. No branch when size == VEC_SIZE. */ @@ -250,7 +258,7 @@ L(movsb): # endif jb L(more_8x_vec_backward) 1: - movq %rdx, %rcx + mov %RDX_LP, %RCX_LP rep movsb L(nop): ret diff --git a/sysdeps/x86_64/multiarch/memrchr-avx2.S b/sysdeps/x86_64/multiarch/memrchr-avx2.S index b41a58bcba..ce488dd9e8 100644 --- a/sysdeps/x86_64/multiarch/memrchr-avx2.S +++ b/sysdeps/x86_64/multiarch/memrchr-avx2.S @@ -32,10 +32,10 @@ ENTRY (__memrchr_avx2) vmovd %esi, %xmm0 vpbroadcastb %xmm0, %ymm0 - subq $VEC_SIZE, %rdx + sub $VEC_SIZE, %RDX_LP jbe L(last_vec_or_less) - addq %rdx, %rdi + add %RDX_LP, %RDI_LP /* Check the last VEC_SIZE bytes. */ vpcmpeqb (%rdi), %ymm0, %ymm1 diff --git a/sysdeps/x86_64/multiarch/memset-avx512-no-vzeroupper.S b/sysdeps/x86_64/multiarch/memset-avx512-no-vzeroupper.S index 689cc1199c..99e255195a 100644 --- a/sysdeps/x86_64/multiarch/memset-avx512-no-vzeroupper.S +++ b/sysdeps/x86_64/multiarch/memset-avx512-no-vzeroupper.S @@ -29,12 +29,16 @@ .section .text.avx512,"ax",@progbits #if defined PIC ENTRY (MEMSET_CHK) - cmpq %rdx, %rcx + cmp %RDX_LP, %RCX_LP jb HIDDEN_JUMPTARGET (__chk_fail) END (MEMSET_CHK) #endif ENTRY (MEMSET) +# ifdef __ILP32__ + /* Clear the upper 32 bits. */ + mov %edx, %edx +# endif vpxor %xmm0, %xmm0, %xmm0 vmovd %esi, %xmm1 lea (%rdi, %rdx), %rsi diff --git a/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S b/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S index dc9cb88b37..a44f1bc3b2 100644 --- a/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S +++ b/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S @@ -75,8 +75,8 @@ .section SECTION(.text),"ax",@progbits #if VEC_SIZE == 16 && IS_IN (libc) ENTRY (__bzero) - movq %rdi, %rax /* Set return value. */ - movq %rsi, %rdx /* Set n. */ + mov %RDI_LP, %RAX_LP /* Set return value. */ + mov %RSI_LP, %RDX_LP /* Set n. */ pxor %xmm0, %xmm0 jmp L(entry_from_bzero) END (__bzero) @@ -86,13 +86,13 @@ weak_alias (__bzero, bzero) #if IS_IN (libc) # if defined SHARED ENTRY_CHK (WMEMSET_CHK_SYMBOL (__wmemset_chk, unaligned)) - cmpq %rdx, %rcx + cmp %RDX_LP, %RCX_LP jb HIDDEN_JUMPTARGET (__chk_fail) END_CHK (WMEMSET_CHK_SYMBOL (__wmemset_chk, unaligned)) # endif ENTRY (WMEMSET_SYMBOL (__wmemset, unaligned)) - shlq $2, %rdx + shl $2, %RDX_LP WMEMSET_VDUP_TO_VEC0_AND_SET_RETURN (%esi, %rdi) jmp L(entry_from_bzero) END (WMEMSET_SYMBOL (__wmemset, unaligned)) @@ -100,13 +100,17 @@ END (WMEMSET_SYMBOL (__wmemset, unaligned)) #if defined SHARED && IS_IN (libc) ENTRY_CHK (MEMSET_CHK_SYMBOL (__memset_chk, unaligned)) - cmpq %rdx, %rcx + cmp %RDX_LP, %RCX_LP jb HIDDEN_JUMPTARGET (__chk_fail) END_CHK (MEMSET_CHK_SYMBOL (__memset_chk, unaligned)) #endif ENTRY (MEMSET_SYMBOL (__memset, unaligned)) MEMSET_VDUP_TO_VEC0_AND_SET_RETURN (%esi, %rdi) +# ifdef __ILP32__ + /* Clear the upper 32 bits. */ + mov %edx, %edx +# endif L(entry_from_bzero): cmpq $VEC_SIZE, %rdx jb L(less_vec) @@ -122,14 +126,14 @@ END (MEMSET_SYMBOL (__memset, unaligned)) # if VEC_SIZE == 16 ENTRY (__memset_chk_erms) - cmpq %rdx, %rcx + cmp %RDX_LP, %RCX_LP jb HIDDEN_JUMPTARGET (__chk_fail) END (__memset_chk_erms) /* Only used to measure performance of REP STOSB. */ ENTRY (__memset_erms) /* Skip zero length. */ - testq %rdx, %rdx + test %RDX_LP, %RDX_LP jnz L(stosb) movq %rdi, %rax ret @@ -141,11 +145,11 @@ ENTRY (MEMSET_SYMBOL (__memset, erms)) L(stosb): /* Issue vzeroupper before rep stosb. */ VZEROUPPER - movq %rdx, %rcx + mov %RDX_LP, %RCX_LP movzbl %sil, %eax - movq %rdi, %rdx + mov %RDI_LP, %RDX_LP rep stosb - movq %rdx, %rax + mov %RDX_LP, %RAX_LP ret # if VEC_SIZE == 16 END (__memset_erms) @@ -155,16 +159,20 @@ END (MEMSET_SYMBOL (__memset, erms)) # if defined SHARED && IS_IN (libc) ENTRY_CHK (MEMSET_CHK_SYMBOL (__memset_chk, unaligned_erms)) - cmpq %rdx, %rcx + cmp %RDX_LP, %RCX_LP jb HIDDEN_JUMPTARGET (__chk_fail) END_CHK (MEMSET_CHK_SYMBOL (__memset_chk, unaligned_erms)) # endif ENTRY (MEMSET_SYMBOL (__memset, unaligned_erms)) MEMSET_VDUP_TO_VEC0_AND_SET_RETURN (%esi, %rdi) - cmpq $VEC_SIZE, %rdx +# ifdef __ILP32__ + /* Clear the upper 32 bits. */ + mov %edx, %edx +# endif + cmp $VEC_SIZE, %RDX_LP jb L(less_vec) - cmpq $(VEC_SIZE * 2), %rdx + cmp $(VEC_SIZE * 2), %RDX_LP ja L(stosb_more_2x_vec) /* From VEC and to 2 * VEC. No branch when size == VEC_SIZE. */ VMOVU %VEC(0), -VEC_SIZE(%rdi,%rdx) diff --git a/sysdeps/x86_64/multiarch/strcmp-avx2.S b/sysdeps/x86_64/multiarch/strcmp-avx2.S index e8397f3b05..78fc116877 100644 --- a/sysdeps/x86_64/multiarch/strcmp-avx2.S +++ b/sysdeps/x86_64/multiarch/strcmp-avx2.S @@ -79,15 +79,15 @@ ENTRY (STRCMP) # ifdef USE_AS_STRNCMP /* Check for simple cases (0 or 1) in offset. */ - cmp $1, %rdx + cmp $1, %RDX_LP je L(char0) jb L(zero) # ifdef USE_AS_WCSCMP /* Convert units: from wide to byte char. */ - shl $2, %rdx + shl $2, %RDX_LP # endif /* Register %r11 tracks the maximum offset. */ - movq %rdx, %r11 + mov %RDX_LP, %R11_LP # endif movl %edi, %eax xorl %edx, %edx diff --git a/sysdeps/x86_64/multiarch/strcmp-sse42.S b/sysdeps/x86_64/multiarch/strcmp-sse42.S index d3c07bd292..a1ebea46fe 100644 --- a/sysdeps/x86_64/multiarch/strcmp-sse42.S +++ b/sysdeps/x86_64/multiarch/strcmp-sse42.S @@ -156,11 +156,11 @@ STRCMP_SSE42: #endif #if defined USE_AS_STRNCMP || defined USE_AS_STRNCASECMP_L - test %rdx, %rdx + test %RDX_LP, %RDX_LP je LABEL(strcmp_exitz) - cmp $1, %rdx + cmp $1, %RDX_LP je LABEL(Byte0) - mov %rdx, %r11 + mov %RDX_LP, %R11_LP #endif mov %esi, %ecx mov %edi, %eax diff --git a/sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S b/sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S index 72bf7e8586..50aca22d2e 100644 --- a/sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S +++ b/sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S @@ -40,8 +40,8 @@ .text ENTRY (STRCPY) # ifdef USE_AS_STRNCPY - mov %rdx, %r8 - test %r8, %r8 + mov %RDX_LP, %R8_LP + test %R8_LP, %R8_LP jz L(ExitZero) # endif mov %rsi, %rcx diff --git a/sysdeps/x86_64/multiarch/strcpy-ssse3.S b/sysdeps/x86_64/multiarch/strcpy-ssse3.S index 9858d0c4d5..0a62814a06 100644 --- a/sysdeps/x86_64/multiarch/strcpy-ssse3.S +++ b/sysdeps/x86_64/multiarch/strcpy-ssse3.S @@ -31,13 +31,13 @@ ENTRY (STRCPY) mov %rsi, %rcx # ifdef USE_AS_STRNCPY - mov %rdx, %r8 + mov %RDX_LP, %R8_LP # endif mov %rdi, %rdx # ifdef USE_AS_STRNCPY - test %r8, %r8 + test %R8_LP, %R8_LP jz L(Exit0) - cmp $8, %r8 + cmp $8, %R8_LP jbe L(StrncpyExit8Bytes) # endif cmpb $0, (%rcx) diff --git a/sysdeps/x86_64/multiarch/strlen-avx2.S b/sysdeps/x86_64/multiarch/strlen-avx2.S index fb2418cddc..645e04461f 100644 --- a/sysdeps/x86_64/multiarch/strlen-avx2.S +++ b/sysdeps/x86_64/multiarch/strlen-avx2.S @@ -42,12 +42,15 @@ ENTRY (STRLEN) # ifdef USE_AS_STRNLEN /* Check for zero length. */ - testq %rsi, %rsi + test %RSI_LP, %RSI_LP jz L(zero) # ifdef USE_AS_WCSLEN - shl $2, %rsi + shl $2, %RSI_LP +# elif defined __ILP32__ + /* Clear the upper 32 bits. */ + movl %esi, %esi # endif - movq %rsi, %r8 + mov %RSI_LP, %R8_LP # endif movl %edi, %ecx movq %rdi, %rdx diff --git a/sysdeps/x86_64/strcmp.S b/sysdeps/x86_64/strcmp.S index e16945b961..f47c8ad45c 100644 --- a/sysdeps/x86_64/strcmp.S +++ b/sysdeps/x86_64/strcmp.S @@ -135,11 +135,11 @@ ENTRY (STRCMP) * This implementation uses SSE to compare up to 16 bytes at a time. */ #if defined USE_AS_STRNCMP || defined USE_AS_STRNCASECMP_L - test %rdx, %rdx + test %RDX_LP, %RDX_LP je LABEL(strcmp_exitz) - cmp $1, %rdx + cmp $1, %RDX_LP je LABEL(Byte0) - mov %rdx, %r11 + mov %RDX_LP, %R11_LP #endif mov %esi, %ecx mov %edi, %eax diff --git a/sysdeps/x86_64/strlen.S b/sysdeps/x86_64/strlen.S index 01cb5fa846..f845f3d46e 100644 --- a/sysdeps/x86_64/strlen.S +++ b/sysdeps/x86_64/strlen.S @@ -59,21 +59,21 @@ ENTRY(strlen) #ifdef AS_STRNLEN /* Do not read anything when n==0. */ - test %rsi, %rsi + test %RSI_LP, %RSI_LP jne L(n_nonzero) xor %rax, %rax ret L(n_nonzero): # ifdef AS_WCSLEN - shlq $2, %rsi + shl $2, %RSI_LP # endif /* Initialize long lived registers. */ - add %rdi, %rsi - mov %rsi, %r10 - and $-64, %r10 - mov %rsi, %r11 + add %RDI_LP, %RSI_LP + mov %RSI_LP, %R10_LP + and $-64, %R10_LP + mov %RSI_LP, %R11_LP #endif pxor %xmm0, %xmm0 diff --git a/sysdeps/x86_64/x32/Makefile b/sysdeps/x86_64/x32/Makefile index f2ebc24fb0..8748956563 100644 --- a/sysdeps/x86_64/x32/Makefile +++ b/sysdeps/x86_64/x32/Makefile @@ -4,3 +4,15 @@ ifeq ($(subdir),math) # 64-bit llround. Add -fno-builtin-lround to silence the compiler. CFLAGS-s_llround.c += -fno-builtin-lround endif + +ifeq ($(subdir),string) +tests += tst-size_t-memchr tst-size_t-memcmp tst-size_t-memcpy \ + tst-size_t-memrchr tst-size_t-memset tst-size_t-strncasecmp \ + tst-size_t-strncmp tst-size_t-strncpy tst-size_t-strnlen \ + tst-size_t-memcmp-2 +endif + +ifeq ($(subdir),wcsmbs) +tests += tst-size_t-wmemchr tst-size_t-wmemcmp tst-size_t-wmemset \ + tst-size_t-wcsncmp tst-size_t-wcsnlen +endif diff --git a/sysdeps/x86_64/x32/test-size_t.h b/sysdeps/x86_64/x32/test-size_t.h new file mode 100644 index 0000000000..78a940863e --- /dev/null +++ b/sysdeps/x86_64/x32/test-size_t.h @@ -0,0 +1,35 @@ +/* Test string/memory functions with size_t in the lower 32 bits of + 64-bit register. + Copyright (C) 2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for 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 TEST_MAIN +#include + +/* On x32, parameter_t may be passed in a 64-bit register with the LEN + field in the lower 32 bits. When the LEN field of 64-bit register + is passed to string/memory function as the size_t parameter, only + the lower 32 bits can be used. */ +typedef struct +{ + union + { + size_t len; + void (*fn) (void); + }; + void *p; +} parameter_t; diff --git a/sysdeps/x86_64/x32/tst-size_t-memchr.c b/sysdeps/x86_64/x32/tst-size_t-memchr.c new file mode 100644 index 0000000000..29a3daf102 --- /dev/null +++ b/sysdeps/x86_64/x32/tst-size_t-memchr.c @@ -0,0 +1,72 @@ +/* Test memchr with size_t in the lower 32 bits of 64-bit register. + Copyright (C) 2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for 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 WIDE +# define TEST_NAME "memchr" +#else +# define TEST_NAME "wmemchr" +#endif /* WIDE */ +#include "test-size_t.h" + +#ifndef WIDE +# define MEMCHR memchr +# define CHAR char +# define UCHAR unsigned char +#else +# include +# define MEMCHR wmemchr +# define CHAR wchar_t +# define UCHAR wchar_t +#endif /* WIDE */ + +IMPL (MEMCHR, 1) + +typedef CHAR * (*proto_t) (const CHAR*, int, size_t); + +static CHAR * +__attribute__ ((noinline, noclone)) +do_memchr (parameter_t a, parameter_t b) +{ + return CALL (&b, a.p, (uintptr_t) b.p, a.len); +} + +static int +test_main (void) +{ + test_init (); + + parameter_t src = { { page_size / sizeof (CHAR) }, buf2 }; + parameter_t c = { { 0 }, (void *) (uintptr_t) 0x12 }; + + int ret = 0; + FOR_EACH_IMPL (impl, 0) + { + c.fn = impl->fn; + CHAR *res = do_memchr (src, c); + if (res) + { + error (0, 0, "Wrong result in function %s: %p != NULL", + impl->name, res); + ret = 1; + } + } + + return ret ? EXIT_FAILURE : EXIT_SUCCESS; +} + +#include diff --git a/sysdeps/x86_64/x32/tst-size_t-memcmp-2.c b/sysdeps/x86_64/x32/tst-size_t-memcmp-2.c new file mode 100644 index 0000000000..d8ae1a0813 --- /dev/null +++ b/sysdeps/x86_64/x32/tst-size_t-memcmp-2.c @@ -0,0 +1,79 @@ +/* Test memcmp with size_t in the lower 32 bits of 64-bit register. + Copyright (C) 2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for 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 TEST_MAIN +#ifdef WIDE +# define TEST_NAME "wmemcmp" +#else +# define TEST_NAME "memcmp" +#endif + +#include "test-size_t.h" + +#ifdef WIDE +# include +# include + +# define MEMCMP wmemcmp +# define CHAR wchar_t +#else +# define MEMCMP memcmp +# define CHAR char +#endif + +IMPL (MEMCMP, 1) + +typedef int (*proto_t) (const CHAR *, const CHAR *, size_t); + +static int +__attribute__ ((noinline, noclone)) +do_memcmp (parameter_t a, parameter_t b) +{ + return CALL (&b, a.p, b.p, a.len); +} + +static int +test_main (void) +{ + test_init (); + + parameter_t dest = { { page_size / sizeof (CHAR) }, buf1 }; + parameter_t src = { { 0 }, buf2 }; + + memcpy (buf1, buf2, page_size); + + CHAR *p = (CHAR *) buf1; + p[page_size / sizeof (CHAR) - 1] = (CHAR) 1; + + int ret = 0; + FOR_EACH_IMPL (impl, 0) + { + src.fn = impl->fn; + int res = do_memcmp (dest, src); + if (res >= 0) + { + error (0, 0, "Wrong result in function %s: %i >= 0", + impl->name, res); + ret = 1; + } + } + + return ret ? EXIT_FAILURE : EXIT_SUCCESS; +} + +#include diff --git a/sysdeps/x86_64/x32/tst-size_t-memcmp.c b/sysdeps/x86_64/x32/tst-size_t-memcmp.c new file mode 100644 index 0000000000..9bd6fdb45a --- /dev/null +++ b/sysdeps/x86_64/x32/tst-size_t-memcmp.c @@ -0,0 +1,76 @@ +/* Test memcmp with size_t in the lower 32 bits of 64-bit register. + Copyright (C) 2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for 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 TEST_MAIN +#ifdef WIDE +# define TEST_NAME "wmemcmp" +#else +# define TEST_NAME "memcmp" +#endif + +#include "test-size_t.h" + +#ifdef WIDE +# include +# include + +# define MEMCMP wmemcmp +# define CHAR wchar_t +#else +# define MEMCMP memcmp +# define CHAR char +#endif + +IMPL (MEMCMP, 1) + +typedef int (*proto_t) (const CHAR *, const CHAR *, size_t); + +static int +__attribute__ ((noinline, noclone)) +do_memcmp (parameter_t a, parameter_t b) +{ + return CALL (&b, a.p, b.p, a.len); +} + +static int +test_main (void) +{ + test_init (); + + parameter_t dest = { { page_size / sizeof (CHAR) }, buf1 }; + parameter_t src = { { 0 }, buf2 }; + + memcpy (buf1, buf2, page_size); + + int ret = 0; + FOR_EACH_IMPL (impl, 0) + { + src.fn = impl->fn; + int res = do_memcmp (dest, src); + if (res) + { + error (0, 0, "Wrong result in function %s: %i != 0", + impl->name, res); + ret = 1; + } + } + + return ret ? EXIT_FAILURE : EXIT_SUCCESS; +} + +#include diff --git a/sysdeps/x86_64/x32/tst-size_t-memcpy.c b/sysdeps/x86_64/x32/tst-size_t-memcpy.c new file mode 100644 index 0000000000..66b71e1749 --- /dev/null +++ b/sysdeps/x86_64/x32/tst-size_t-memcpy.c @@ -0,0 +1,58 @@ +/* Test memcpy with size_t in the lower 32 bits of 64-bit register. + Copyright (C) 2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for 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 TEST_NAME "memcpy" +#include "test-size_t.h" + +IMPL (memcpy, 1) + +typedef void *(*proto_t) (void *, const void *, size_t); + +static void * +__attribute__ ((noinline, noclone)) +do_memcpy (parameter_t a, parameter_t b) +{ + return CALL (&b, a.p, b.p, a.len); +} + +static int +test_main (void) +{ + test_init (); + + parameter_t dest = { { page_size }, buf1 }; + parameter_t src = { { 0 }, buf2 }; + + int ret = 0; + FOR_EACH_IMPL (impl, 0) + { + src.fn = impl->fn; + do_memcpy (dest, src); + int res = memcmp (dest.p, src.p, dest.len); + if (res) + { + error (0, 0, "Wrong result in function %s: %i != 0", + impl->name, res); + ret = 1; + } + } + + return ret ? EXIT_FAILURE : EXIT_SUCCESS; +} + +#include diff --git a/sysdeps/x86_64/x32/tst-size_t-memrchr.c b/sysdeps/x86_64/x32/tst-size_t-memrchr.c new file mode 100644 index 0000000000..c83699c097 --- /dev/null +++ b/sysdeps/x86_64/x32/tst-size_t-memrchr.c @@ -0,0 +1,57 @@ +/* Test memrchr with size_t in the lower 32 bits of 64-bit register. + Copyright (C) 2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for 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 TEST_NAME "memrchr" +#include "test-size_t.h" + +IMPL (memchr, 1) + +typedef void * (*proto_t) (const void *, int, size_t); + +static void * +__attribute__ ((noinline, noclone)) +do_memrchr (parameter_t a, parameter_t b) +{ + return CALL (&b, a.p, (uintptr_t) b.p, a.len); +} + +static int +test_main (void) +{ + test_init (); + + parameter_t src = { { page_size }, buf2 }; + parameter_t c = { { 0 }, (void *) (uintptr_t) 0x12 }; + + int ret = 0; + FOR_EACH_IMPL (impl, 0) + { + c.fn = impl->fn; + void * res = do_memrchr (src, c); + if (res) + { + error (0, 0, "Wrong result in function %s: %p != NULL", + impl->name, res); + ret = 1; + } + } + + return ret ? EXIT_FAILURE : EXIT_SUCCESS; +} + +#include diff --git a/sysdeps/x86_64/x32/tst-size_t-memset.c b/sysdeps/x86_64/x32/tst-size_t-memset.c new file mode 100644 index 0000000000..2c367af6cd --- /dev/null +++ b/sysdeps/x86_64/x32/tst-size_t-memset.c @@ -0,0 +1,73 @@ +/* Test memset with size_t in the lower 32 bits of 64-bit register. + Copyright (C) 2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for 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 WIDE +# define TEST_NAME "wmemset" +#else +# define TEST_NAME "memset" +#endif /* WIDE */ + +#include "test-size_t.h" + +#ifdef WIDE +# include +# define MEMSET wmemset +# define CHAR wchar_t +#else +# define MEMSET memset +# define CHAR char +#endif /* WIDE */ + +IMPL (MEMSET, 1) + +typedef CHAR *(*proto_t) (CHAR *, int, size_t); + +static void * +__attribute__ ((noinline, noclone)) +do_memset (parameter_t a, parameter_t b) +{ + return CALL (&b, a.p, (uintptr_t) b.p, a.len); +} + +static int +test_main (void) +{ + test_init (); + + CHAR ch = 0x23; + parameter_t src = { { page_size / sizeof (CHAR) }, buf2 }; + parameter_t c = { { 0 }, (void *) (uintptr_t) ch }; + + int ret = 0; + FOR_EACH_IMPL (impl, 0) + { + c.fn = impl->fn; + CHAR *p = (CHAR *) do_memset (src, c); + size_t i; + for (i = 0; i < src.len; i++) + if (p[i] != ch) + { + error (0, 0, "Wrong result in function %s", impl->name); + ret = 1; + } + } + + return ret ? EXIT_FAILURE : EXIT_SUCCESS; +} + +#include diff --git a/sysdeps/x86_64/x32/tst-size_t-strncasecmp.c b/sysdeps/x86_64/x32/tst-size_t-strncasecmp.c new file mode 100644 index 0000000000..862335937b --- /dev/null +++ b/sysdeps/x86_64/x32/tst-size_t-strncasecmp.c @@ -0,0 +1,59 @@ +/* Test strncaecmp with size_t in the lower 32 bits of 64-bit register. + Copyright (C) 2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for 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 TEST_NAME "strncasecmp" +#include "test-size_t.h" + +IMPL (strncasecmp, 1) + +typedef int (*proto_t) (const char *, const char *, size_t); + +static int +__attribute__ ((noinline, noclone)) +do_strncasecmp (parameter_t a, parameter_t b) +{ + return CALL (&b, a.p, b.p, a.len); +} + +static int +test_main (void) +{ + test_init (); + + parameter_t dest = { { page_size }, buf1 }; + parameter_t src = { { 0 }, buf2 }; + + strncpy ((char *) buf1, (const char *) buf2, page_size); + + int ret = 0; + FOR_EACH_IMPL (impl, 0) + { + src.fn = impl->fn; + int res = do_strncasecmp (dest, src); + if (res) + { + error (0, 0, "Wrong result in function %s: %i != 0", + impl->name, res); + ret = 1; + } + } + + return ret ? EXIT_FAILURE : EXIT_SUCCESS; +} + +#include diff --git a/sysdeps/x86_64/x32/tst-size_t-strncmp.c b/sysdeps/x86_64/x32/tst-size_t-strncmp.c new file mode 100644 index 0000000000..54e6bd83ef --- /dev/null +++ b/sysdeps/x86_64/x32/tst-size_t-strncmp.c @@ -0,0 +1,78 @@ +/* Test strncmp with size_t in the lower 32 bits of 64-bit register. + Copyright (C) 2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for 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 WIDE +# define TEST_NAME "wcsncmp" +#else +# define TEST_NAME "strncmp" +#endif + +#include "test-size_t.h" + +#ifdef WIDE +# include + +# define STRNCMP wcsncmp +# define STRNCPY wcsncpy +# define CHAR wchar_t +#else +# define STRNCMP strncmp +# define STRNCPY strncpy +# define CHAR char +#endif + +IMPL (STRNCMP, 1) + +typedef int (*proto_t) (const CHAR *, const CHAR *, size_t); + + +static int +__attribute__ ((noinline, noclone)) +do_strncmp (parameter_t a, parameter_t b) +{ + return CALL (&b, a.p, b.p, a.len); +} + +static int +test_main (void) +{ + test_init (); + + size_t size = page_size / sizeof (CHAR); + parameter_t dest = { { size }, buf1 }; + parameter_t src = { { 0 }, buf2 }; + + STRNCPY ((CHAR *) buf1, (const CHAR *) buf2, size); + + int ret = 0; + FOR_EACH_IMPL (impl, 0) + { + src.fn = impl->fn; + int res = do_strncmp (dest, src); + if (res) + { + error (0, 0, "Wrong result in function %s: %i != 0", + impl->name, res); + ret = 1; + } + } + + return ret ? EXIT_FAILURE : EXIT_SUCCESS; +} + +#include diff --git a/sysdeps/x86_64/x32/tst-size_t-strncpy.c b/sysdeps/x86_64/x32/tst-size_t-strncpy.c new file mode 100644 index 0000000000..4dec71e6b3 --- /dev/null +++ b/sysdeps/x86_64/x32/tst-size_t-strncpy.c @@ -0,0 +1,58 @@ +/* Test strncpy with size_t in the lower 32 bits of 64-bit register. + Copyright (C) 2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for 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 TEST_NAME "strncpy" +#include "test-size_t.h" + +IMPL (strncpy, 1) + +typedef char *(*proto_t) (char *, const char*, size_t); + +static void * +__attribute__ ((noinline, noclone)) +do_strncpy (parameter_t a, parameter_t b) +{ + return CALL (&b, a.p, b.p, a.len); +} + +static int +test_main (void) +{ + test_init (); + + parameter_t dest = { { page_size }, buf1 }; + parameter_t src = { { 0 }, buf2 }; + + int ret = 0; + FOR_EACH_IMPL (impl, 0) + { + src.fn = impl->fn; + do_strncpy (dest, src); + int res = strncmp (dest.p, src.p, dest.len); + if (res) + { + error (0, 0, "Wrong result in function %s: %i != 0", + impl->name, res); + ret = 1; + } + } + + return ret ? EXIT_FAILURE : EXIT_SUCCESS; +} + +#include diff --git a/sysdeps/x86_64/x32/tst-size_t-strnlen.c b/sysdeps/x86_64/x32/tst-size_t-strnlen.c new file mode 100644 index 0000000000..690a4a8a31 --- /dev/null +++ b/sysdeps/x86_64/x32/tst-size_t-strnlen.c @@ -0,0 +1,72 @@ +/* Test strnlen with size_t in the lower 32 bits of 64-bit register. + Copyright (C) 2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for 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 WIDE +# define TEST_NAME "wcsnlen" +#else +# define TEST_NAME "strnlen" +#endif /* WIDE */ + +#include "test-size_t.h" + +#ifdef WIDE +# include +# define STRNLEN wcsnlen +# define CHAR wchar_t +#else +# define STRNLEN strnlen +# define CHAR char +#endif /* WIDE */ + +IMPL (STRNLEN, 1) + +typedef size_t (*proto_t) (const CHAR *, size_t); + +static size_t +__attribute__ ((noinline, noclone)) +do_strnlen (parameter_t a, parameter_t b) +{ + return CALL (&a, a.p, b.len); +} + +static int +test_main (void) +{ + test_init (); + + size_t size = page_size / sizeof (CHAR); + parameter_t src = { { 0 }, buf2 }; + parameter_t c = { { size }, (void *) (uintptr_t) 'a' }; + + int ret = 0; + FOR_EACH_IMPL (impl, 0) + { + src.fn = impl->fn; + size_t res = do_strnlen (src, c); + if (res != size) + { + error (0, 0, "Wrong result in function %s: 0x%x != 0x%x", + impl->name, res, size); + ret = 1; + } + } + + return ret ? EXIT_FAILURE : EXIT_SUCCESS; +} + +#include diff --git a/sysdeps/x86_64/x32/tst-size_t-wcsncmp.c b/sysdeps/x86_64/x32/tst-size_t-wcsncmp.c new file mode 100644 index 0000000000..4829647c19 --- /dev/null +++ b/sysdeps/x86_64/x32/tst-size_t-wcsncmp.c @@ -0,0 +1,20 @@ +/* Test wcsncmp with size_t in the lower 32 bits of 64-bit register. + Copyright (C) 2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for 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 WIDE 1 +#include "tst-size_t-strncmp.c" diff --git a/sysdeps/x86_64/x32/tst-size_t-wcsnlen.c b/sysdeps/x86_64/x32/tst-size_t-wcsnlen.c new file mode 100644 index 0000000000..093b4bbe1b --- /dev/null +++ b/sysdeps/x86_64/x32/tst-size_t-wcsnlen.c @@ -0,0 +1,20 @@ +/* Test wcsnlen with size_t in the lower 32 bits of 64-bit register. + Copyright (C) 2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for 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 WIDE 1 +#include "tst-size_t-strnlen.c" diff --git a/sysdeps/x86_64/x32/tst-size_t-wmemchr.c b/sysdeps/x86_64/x32/tst-size_t-wmemchr.c new file mode 100644 index 0000000000..877801d646 --- /dev/null +++ b/sysdeps/x86_64/x32/tst-size_t-wmemchr.c @@ -0,0 +1,20 @@ +/* Test wmemchr with size_t in the lower 32 bits of 64-bit register. + Copyright (C) 2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for 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 WIDE 1 +#include "tst-size_t-memchr.c" diff --git a/sysdeps/x86_64/x32/tst-size_t-wmemcmp.c b/sysdeps/x86_64/x32/tst-size_t-wmemcmp.c new file mode 100644 index 0000000000..e8b5ffd0d5 --- /dev/null +++ b/sysdeps/x86_64/x32/tst-size_t-wmemcmp.c @@ -0,0 +1,20 @@ +/* Test wmemcmp with size_t in the lower 32 bits of 64-bit register. + Copyright (C) 2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for 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 WIDE 1 +#include "tst-size_t-memcmp.c" diff --git a/sysdeps/x86_64/x32/tst-size_t-wmemset.c b/sysdeps/x86_64/x32/tst-size_t-wmemset.c new file mode 100644 index 0000000000..955eb488c2 --- /dev/null +++ b/sysdeps/x86_64/x32/tst-size_t-wmemset.c @@ -0,0 +1,20 @@ +/* Test wmemset with size_t in the lower 32 bits of 64-bit register. + Copyright (C) 2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for 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 WIDE 1 +#include "tst-size_t-memset.c" diff --git a/time/tzfile.c b/time/tzfile.c index 2a385b92bc..ea6e940303 100644 --- a/time/tzfile.c +++ b/time/tzfile.c @@ -410,7 +410,8 @@ __tzfile_read (const char *file, size_t extra, char **extrap) /* First "register" all timezone names. */ for (i = 0; i < num_types; ++i) - (void) __tzstring (&zone_names[types[i].idx]); + if (__tzstring (&zone_names[types[i].idx]) == NULL) + goto ret_free_transitions; /* Find the standard and daylight time offsets used by the rule file. We choose the offsets in the types of each flavor that are