GIT update of https://sourceware.org/git/glibc.git/release/2.28/master from glibc-2.28
Gbp-Pq: Name git-updates.diff
+2019-04-23 Adhemerval Zanella <adhemerval.zanella@linaro.org>
+
+ [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 <tamuki@linet.gr.jp>
+
+ [BZ #22964]
+ * localedata/locales/ja_JP (LC_TIME): Add entry for the new Japanese
+ era.
+
+2019-03-21 Stefan Liebler <stli@linux.ibm.com>
+
+ * sysdeps/s390/dl-procinfo.h (HWCAP_IMPORTANT):
+ Add HWCAP_S390_VX and HWCAP_S390_VXE.
+
+2019-01-31 Paul Eggert <eggert@cs.ucla.edu>
+
+ 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 <schwab@suse.de>
+
+ [BZ #23864]
+ * sysdeps/unix/sysv/linux/riscv/kernel-features.h
+ (__ASSUME_SET_ROBUST_LIST) [__LINUX_KERNEL_VERSION < 0x041400]:
+ Undef.
+
+2018-09-21 Adhemerval Zanella <adhemerval.zanella@linaro.org>
+
+ * 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 <jimw@sifive.com>
+
+ [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 <carlos@redhat.com>
+ Torvald Riegel <triegel@redhat.com>
+ Rik Prohaska <prohaska7@gmail.com>
+
+ [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 <fweimer@redhat.com>
+
+ [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 <stli@linux.ibm.com>
+
+ [BZ #24180]
+ * nptl/pthread_mutex_trylock.c (__pthread_mutex_trylock):
+ Add compiler barriers and comments.
+
+2019-02-04 Florian Weimer <fweimer@redhat.com>
+
+ [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 <arpa/inet.h> and change visibility of
+ __inet_aton_exact.
+
+2019-01-21 Florian Weimer <fweimer@redhat.com>
+
+ [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 <support/test-driver.c>.
+ (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 <fweimer@redhat.com>
+
+ [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 <fweimer@redhat.com>
+
+ * resolv/inet_addr.c: Reformat to GNU style.
+ (__inet_addr, __inet_aton): Update comment.
+
+2019-02-04 H.J. Lu <hongjiu.lu@intel.com>
+
+ [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 <hongjiu.lu@intel.com>
+
+ [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 <hongjiu.lu@intel.com>
+
+ [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 <hongjiu.lu@intel.com>
+
+ [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 <hongjiu.lu@intel.com>
+
+ [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 <hongjiu.lu@intel.com>
+
+ [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 <hongjiu.lu@intel.com>
+
+ [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 <hongjiu.lu@intel.com>
+
+ [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 <hongjiu.lu@intel.com>
+
+ [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 <tuliom@linux.ibm.com>
+
+ * math/libm-test-fma.inc (fma_test_data): Set
+ XFAIL_ROUNDING_IBM128_LIBGCC to more tests.
+
+2019-01-07 Aurelien Jarno <aurelien@aurel32.net>
+
+ [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 <Martin.Jansa@gmail.com>
+
+ [BZ #19444]
+ * sysdeps/ieee754/soft-fp/s_fdiv.c: Include <libc-diag.h> and use
+ DIAG_PUSH_NEEDS_COMMENT, DIAG_IGNORE_NEEDS_COMMENT and
+ DIAG_POP_NEEDS_COMMENT to disable -Wmaybe-uninitialized.
+
+2019-01-02 Aurelien Jarno <aurelien@aurel32.net>
+
+ [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 <hongjiu.lu@intel.com>
+
+ [BZ #24022]
+ * sysdeps/unix/sysv/linux/riscv/flush-icache.c: Check if
+ <asm/syscalls.h> exists with __has_include__ before including it.
+
+2019-01-02 Florian Weimer <fweimer@redhat.com>
+
+ [BZ #24018]
+ * intl/dcigettext.c (DCIGETTEXT): Do not return NULL on asprintf
+ failure.
+
+2018-12-31 Florian Weimer <fw@deneb.enyo.de>
+
+ [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 <aurelien@aurel32.net>
+
+ * sysdeps/alpha/fpu/libm-test-ulps: Regenerated.
+
+2018-12-18 Adhemerval Zanella <adhemerval.zanella@linaro.org>
+ James Clarke <jrtc27@jrtc27.com>
+
+ [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 <schwab@suse.de>
+
+ [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 <fweimer@redhat.com>
+
+ * 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 <schwab@suse.de>
+
+ [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 <tuliom@linux.ibm.com>
+
+ [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 <dj@redhat.com>
+
+ [BZ #23907]
+ * malloc/tst-tcfree3.c: New.
+ * malloc/Makefile: Add it.
+
+2018-12-07 Florian Weimer <fweimer@redhat.com>
+
+ [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 <fweimer@redhat.com>
+
+ * 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 <fweimer@redhat.com>
+
+ * 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 <fweimer@redhat.com>
+
+ * support/support.h (support_quote_string): Do not use str
+ parameter name.
+
+2018-11-27 Florian Weimer <fweimer@redhat.com>
+
+ * 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 <fweimer@redhat.com>
+
+ [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 <tuliom@linux.ibm.com>
+
+ [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 <fweimer@redhat.com>
+
+ [BZ #23907]
+ * malloc/malloc.c (_int_free): Validate tc_idx before checking for
+ double-frees.
+
+
+2018-11-20 DJ Delorie <dj@redhat.com>
+
+ * 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 <fweimer@redhat.com>
+
+ [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 <fweimer@redhat.com>
+
+ 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 <szabolcs.nagy@arm.com>
+
+ * libio/tst-readline.c (TIMEOUT): Define.
+
+2018-10-22 Joseph Myers <joseph@codesourcery.com>
+
+ * sysdeps/unix/sysv/linux/syscall-names.list: Update kernel
+ version to 4.19.
+
+2018-09-18 Paul Eggert <eggert@cs.ucla.edu>
+
+ 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 <ppluzhnikov@google.com>
+
+ [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 <fweimer@redhat.com>
+
+ [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 <dj@delorie.com>
+
+ * malloc/malloc.c (_int_free): Check for corrupt prev_size vs size.
+ (malloc_consolidate): Likewise.
+
+2018-08-16 Pochang Chen <johnchen902@gmail.com>
+
+ * malloc/malloc.c (_int_malloc.c): Verify size of top chunk.
+
+2018-08-13 Joseph Myers <joseph@codesourcery.com>
+
+ * 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á <ahajkova@redhat.com>
+
+ [BZ #17630]
+ * resolv/tst-resolv-network.c: Add test for getnetbyname.
+
+2018-11-08 H.J. Lu <hongjiu.lu@intel.com>
+
+ [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 <schwab@suse.de>
+
+ [BZ #22927]
+ * resolv/gai_misc.c (__gai_enqueue_request): Don't crash if
+ creating the first helper thread failed.
+
+2018-10-23 Adhemerval Zanella <adhemerval.zanella@linaro.org>
+
+ [BZ #23709]
+ * sysdeps/x86/cpu-features.c (init_cpu_features): Set TSX bits
+ independently of other flags.
+
+2018-10-30 Florian Weimer <fweimer@redhat.com>
+
+ * stdlib/tst-strtod-overflow.c (do_test): Switch to
+ support_blob_repeat.
+
+2018-10-30 Florian Weimer <fweimer@redhat.com>
+
+ * support/blob_repeat.c (allocate_big): Call mkstemp directly.
+
+2018-10-30 Florian Weimer <fweimer@redhat.com>
+
+ * stdlib/test-bz22786.c (do_test): Additional free calls to avoid
+ memory leaks.
+
+2018-10-30 Florian Weimer <fweimer@redhat.com>
+
+ 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 <stli@linux.ibm.com>
+
+ * stdlib/test-bz22786.c (do_test): Return EXIT_UNSUPPORTED
+ if malloc fails.
+
+2018-08-24 Paul Pluzhnikov <ppluzhnikov@google.com>
+
+ [BZ #23400]
+ * stdlib/test-bz22786.c (do_test): Fix undefined behavior, don't
+ create temporary files in source tree.
+
+2018-10-26 Szabolcs Nagy <szabolcs.nagy@arm.com>
+
+ [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 <fweimer@redhat.com>
+
+ [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 <malakhov@mcst.ru>
+
+ [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 <stli@linux.ibm.com>
+
+ [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 <hongjiu.lu@intel.com>
+
+ [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 <digitalfreak@lingonborough.com>
+
+ [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 <adhemerval.zanella@linaro.org>
+
+ [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 <schwab@suse.de>
+
+ [BZ #23717]
+ * stdlib/tst-setcontext9.c (f1a): Make st2 static.
+ (do_test): Make st1 static.
+
+2018-09-21 H.J. Lu <hongjiu.lu@intel.com>
+ Xuepeng Guo <xuepeng.guo@intel.com>
+
+ [BZ #23606]
+ * sysdeps/i386/start.S: Include <sysdep.h>
+ (_start): Use ENTRY/END to insert ENDBR32 at entry when CET is
+ enabled. Add cfi_undefined (eip).
+
+2018-09-19 Wilco Dijkstra <wdijkstr@arm.com>
+
+ [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 <carlos@redhat.com>
+
+ * 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 <fweimer@redhat.com>
+
+ * misc/tst-gethostid.c: New file.
+ * misc/Makefile [$(build-shared)] (tests): Add tst-gethostid.
+ (tst-gethostid): Link with -ldl.
+
+2018-09-20 Mingli Yu <Mingli.Yu@windriver.com>
+
+ * sysdeps/unix/sysv/linux/gethostid.c (gethostid): Check for NULL
+ value from gethostbyname_r.
+
+2018-09-06 Stefan Liebler <stli@linux.ibm.com>
+
+ * sysdeps/unix/sysv/linux/spawni.c (maybe_script_execute):
+ Increment size of new_argv by one.
+
+2018-08-28 Florian Weimer <fweimer@redhat.com>
+
+ [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 <eggert@cs.ucla.edu>
+
+ [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 <bugs@feusi.co> 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 <martin.kuchta@netapp.com>
+ Torvald Riegel <triegel@redhat.com>
+
+ [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 <dj@redhat.com>
+
+ * 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 <fweimer@redhat.com>
+
+ [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 <fweimer@redhat.com>
+
+ * nscd/nscd_conf.c (nscd_parse_file): Deallocate old storage for
+ server_user, stat_user.
+
+2018-08-13 Florian Weimer <fweimer@redhat.com>
+
+ * misc/error.c (error): Add missing va_end call.
+ (error_at_line): Likewise.
+
+2018-08-10 Florian Weimer <fweimer@redhat.com>
+
+ [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 <samuel.thibault@ens-lyon.org>
+
+ * 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 <carlos@redhat.com>
* version.h (RELEASE): Set to "stable".
# 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),)
Please send GNU C library bug reports via <https://sourceware.org/bugzilla/>
using `glibc' in the "product" field.
\f
+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 <asm/syscalls.h>
+ [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.
+\f
Version 2.28
Major new features:
[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)
\f
Version 2.27
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
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
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;
+ }
}
}
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 \
$(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
/* 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
/* 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);
#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;
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
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)
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;
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.
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)
{
}
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)
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);
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')
}
while (list != 0);
- out:
scratch_buffer_free (&tmpbuf);
return status;
}
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
-#include <alloca.h>
+#define _FILE_OFFSET_BITS 64
+
#include <argp.h>
-#include <assert.h>
#include <dirent.h>
-#include <elf.h>
-#include <errno.h>
#include <error.h>
#include <fcntl.h>
#include <libintl.h>
-#include <link.h>
-#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
#include <unistd.h>
#include <sys/ptrace.h>
-#include <sys/stat.h>
#include <sys/wait.h>
#include <scratch_buffer.h>
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);
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);
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 *) "<program name undetermined>";
+ /* Default stack allocation is at least 1024. */
+ snprintf (exe.data, exe.length, "<program name undetermined>");
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. */
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;
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;
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;
}
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/<pid>/mem file. */
+ int memfd = openat (dfd, "mem", O_RDONLY);
if (memfd == -1)
goto no_info;
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);
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <unwind.h>
+#include <unistd.h>
+#include <support/test-driver.h>
+
+#if USE_PTHREADS
+# include <pthread.h>
+# include <error.h>
+#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
+}
/* 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
__cthread_keycreate;
__cthread_getspecific;
__cthread_setspecific;
+ __pthread_getspecific;
+ __pthread_setspecific;
__pthread_getattr_np;
__pthread_attr_getstack;
}
#include <inet/arpa/inet.h>
#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;
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. */
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,
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.
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+/* This test checks for a descriptor leak in case of a long interface
+ name (CVE-2018-19591, bug 23927). */
+
+#include <errno.h>
+#include <net/if.h>
+#include <netdb.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/descriptors.h>
+#include <support/support.h>
+
+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 <support/test-driver.c>
int ret = __asprintf (&xdirname, "%s/%s", cwd, dirname);
free (cwd);
if (ret < 0)
- return NULL;
+ goto return_untranslated;
dirname = xdirname;
}
#ifndef IN_LIBGLOCALE
return 0;
}
+#define TIMEOUT 100
#define PREPARE prepare
#include <support/test-driver.c>
t_fmt_ampm "%p%I<U6642>%M<U5206>%S<U79D2>"
-era "+:2:1990//01//01:+*:<U5E73><U6210>:%EC%Ey<U5E74>";/
+era "+:2:2020//01//01:+*:<U4EE4><U548C>:%EC%Ey<U5E74>";/
+ "+:1:2019//05//01:2019//12//31:<U4EE4><U548C>:%EC<U5143><U5E74>";/
+ "+:2:1990//01//01:2019//04//30:<U5E73><U6210>:%EC%Ey<U5E74>";/
"+:1:1989//01//08:1989//12//31:<U5E73><U6210>:%EC<U5143><U5E74>";/
"+:2:1927//01//01:1989//01//07:<U662D><U548C>:%EC%Ey<U5E74>";/
"+:1:1926//12//25:1926//12//31:<U662D><U548C>:%EC<U5143><U5E74>";/
END LC_NUMERIC
LC_TIME
-abday "sab";"ata";/
+abday "sap";"ata";/
"mar";"pin";/
"sis";"tal";/
"arf"
-day "sabaat";/
+day "sapaat";/
"ataasinngorneq";/
"marlunngorneq";/
"pingasunngorneq";/
tst-malloc_info \
tst-malloc-too-large \
tst-malloc-stats-cancellation \
+ tst-tcfree1 tst-tcfree2 tst-tcfree3 \
tests-static := \
tst-interpose-static-nothread \
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
{
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]);
assert (tcache->entries[tc_idx] > 0);
tcache->entries[tc_idx] = e->next;
--(tcache->counts[tc_idx]);
+ e->key = NULL;
return (void *) e;
}
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
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;
#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^<size_t> 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
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);
}
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);
}
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))
}
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);
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <error.h>
+#include <limits.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/signal.h>
+
+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 <support/test-driver.c>
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <error.h>
+#include <limits.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/signal.h>
+
+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<COUNT; i++)
+ ptrs[i] = malloc (20);
+ for (i=0; i<COUNT; i++)
+ free (ptrs[i]);
+ free (ptrs[0]);
+
+ printf("FAIL: tcache double free\n");
+ return 1;
+}
+
+#define TEST_FUNCTION do_test
+#define EXPECTED_SIGNAL SIGABRT
+#include <support/test-driver.c>
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <malloc.h>
+#include <string.h>
+
+/* 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 <support/test-driver.c>
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),
};
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
$(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)
va_start (args, message);
error_tail (status, errnum, message, args);
+ va_end (args);
#ifdef _LIBC
_IO_funlockfile (stderr);
va_start (args, message);
error_tail (status, errnum, message, args);
+ va_end (args);
#ifdef _LIBC
_IO_funlockfile (stderr);
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <gnu/lib-names.h>
+#include <nss.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/namespace.h>
+#include <support/support.h>
+#include <support/temp_file.h>
+#include <support/xdlfcn.h>
+#include <support/xstdio.h>
+#include <support/xunistd.h>
+#include <unistd.h>
+
+/* 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 <support/test-driver.c>
#include <limits.h>
#include <support/check.h>
-static void
-do_test_with_invalid_flags (void)
-{
#ifndef RWF_HIPRI
# define RWF_HIPRI 0
#endif
#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);
{
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);
}
{
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);
}
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 \
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 \
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)
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
$(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:
};
#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
{
/* 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);
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;
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;
{
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;
}
int
pthread_mutex_getprioceiling (const pthread_mutex_t *mutex, int *prioceiling)
{
- if (__builtin_expect ((mutex->__data.__kind
+ /* See concurrency notes regarding __kind in struct __pthread_mutex_s
+ in sysdeps/nptl/bits/thread-shared-types.h. */
+ if (__builtin_expect ((atomic_load_relaxed (&(mutex->__data.__kind))
& PTHREAD_MUTEX_PRIO_PROTECT_NP) == 0, 0))
return EINVAL;
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)
{
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)
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
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);
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)
{
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;
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
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. */
/* 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))
{
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)
{
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;
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))
{
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
/* 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
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;
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);
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;
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;
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;
{
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. */
{
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;
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;
/* 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
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);
}
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;
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))
/* 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.
/* 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));
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,
/* 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;
&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;
}
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--)
{
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);
}
}
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <elf.h>
+#include <link.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+
+/* 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;
+}
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+/* Define all the retNumN functions in a library. */
+#define definenum
+#include "tst-audit-threads.h"
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+/* 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 <support/xthread.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <sys/sysinfo.h>
+
+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;
+}
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+/* 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 ();
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <support/support.h>
+#include <support/xthread.h>
+
+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 <support/test-driver.c>
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <support/xthread.h>
+
+/* 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 <support/test-driver.c>
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+/* 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <support/xthread.h>
+#include <errno.h>
+
+/* 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 <support/test-driver.c>
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+/* 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <support/xthread.h>
+#include <errno.h>
+
+/* 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 <support/test-driver.c>
--- /dev/null
+#define USE_PTHREADS 1
+#include "../elf/tst-unwind-main.c"
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)
/* 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
#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 <arpa/inet.h>
+__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
#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
/* 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;
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))
{
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))
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;
}
out:
- free (buffer);
-
*resultp = dataset;
return timeout;
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 =
.key_len = group_len
};
timeout = addgetnetgrentX (db, -1, &req_get, group, uid, NULL, NULL,
- &result);
+ &result, &tofree);
}
struct indataset
++dh->nreloads;
if (cacheable)
pthread_rwlock_unlock (&db->lock);
- return timeout;
+ goto out;
}
if (he == NULL)
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);
}
.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);
}
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <arpa/inet.h>
+
+/* We do not want to export __inet_aton_exact. Get the prototype and
+ change the visibility to hidden. */
+#include <arpa/inet.h>
+__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 <resolv/inet_addr.c>
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)
{
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);
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
$(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
#include "nsswitch.h"
#ifdef USE_NSCD
-# define inet_aton __inet_aton
# include <nscd/nscd_proto.h>
#endif
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);
{
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);
if (first_unused[room_left - 1] != '\xff')
{
free (old_line);
+ fclose (listfile);
goto no_more_room;
}
+ __alignof__ (char *)))
{
free (old_line);
+ fclose (listfile);
goto no_more_room;
}
room_left -= ((first_unused - cp)
/* 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;
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <aliases.h>
+#include <array_length.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <gnu/lib-names.h>
+#include <nss.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/namespace.h>
+#include <support/support.h>
+#include <support/temp_file.h>
+#include <support/test-driver.h>
+#include <support/xstdio.h>
+#include <support/xunistd.h>
+
+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 <support/test-driver.c>
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
$(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
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)
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)
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;
}
}
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+/* This test constructs various patterns in an attempt to trigger
+ over-reading the regular expression compiler, such as bug
+ 23578. */
+
+#include <array_length.h>
+#include <errno.h>
+#include <locale.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/next_to_fault.h>
+#include <support/support.h>
+#include <support/test-driver.h>
+#include <wchar.h>
+
+/* 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 <support/test-driver.c>
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
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))
$(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: \
__h_errno; __resp;
__res_iclose;
+ __inet_aton_exact;
__inet_pton_length;
__resolv_context_get;
__resolv_context_get_preinit;
/* 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;
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
/*
* Copyright (c) 1983, 1990, 1993
* The Regents of the University of California. All rights reserved.
#include <limits.h>
#include <errno.h>
-/*
- * 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)
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);
}
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)
{
*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);
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)
{
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);
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)
{
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))
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))
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);
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <array_length.h>
#include <stdio.h>
#include <stdint.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
-
-static struct tests
+static const struct tests
{
const char *input;
int valid;
{ "-1", 0, 0 },
{ "256", 1, 0x00000100 },
{ "256.", 0, 0 },
+ { "255a", 0, 0 },
{ "256a", 0, 0 },
{ "0x100", 1, 0x00000100 },
{ "0200.0x123456", 1, 0x80123456 },
{ "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 },
};
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;
return result;
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <arpa/inet.h>
+#include <support/check.h>
+
+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 <support/test-driver.c>
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);
}
"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,
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <netdb.h>
+#include <stdlib.h>
+#include <support/check.h>
+#include <support/check_nss.h>
+#include <support/resolv_test.h>
+#include <support/support.h>
+
+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 <support/test-driver.c>
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <array_length.h>
+#include <netdb.h>
+#include <support/check.h>
+#include <support/check_nss.h>
+#include <support/resolv_test.h>
+#include <support/support.h>
+
+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 <support/test-driver.c>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <support/blob_repeat.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/temp_file.h>
#include <support/test-driver.h>
#include <libc-diag.h>
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);
/* Cleanup. */
unlink (lnk);
- rmdir (dir);
+ support_blob_repeat_free (&repeat);
+ free (lnk);
+ free (dir);
return 0;
}
}
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)
{
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)
{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <support/blob_repeat.h>
+#include <support/test-driver.h>
#define EXPONENT "e-2147483649"
#define SIZE 214748364
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;
}
# 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
/* 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)
#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))
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <string.h>
+
+#include <support/check.h>
+#include <support/support.h>
+
+/* 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 <support/test-driver.c>
}
}
+#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)
{
check1 ();
check2 ();
+ pr23637 ();
printf ("%23s", "");
FOR_EACH_IMPL (impl, 0)
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);
extra-libs-noinstall := $(extra-libs)
libsupport-routines = \
+ blob_repeat \
check \
check_addrinfo \
check_dns_packet \
support_capture_subprocess \
support_capture_subprocess_check \
support_chroot \
+ support_descriptors \
support_enter_mount_namespace \
support_enter_network_namespace \
support_format_address_family \
support_isolate_in_subprocess \
support_openpty \
support_quote_blob \
+ support_quote_string \
support_record_failure \
support_run_diff \
support_shared_allocate \
xpthread_mutexattr_settype \
xpthread_once \
xpthread_rwlock_init \
+ xpthread_rwlock_destroy \
xpthread_rwlock_rdlock \
xpthread_rwlock_unlock \
xpthread_rwlock_wrlock \
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 \
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/blob_repeat.h>
+#include <support/check.h>
+#include <support/test-driver.h>
+#include <support/support.h>
+#include <support/xunistd.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <wchar.h>
+
+/* 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 <malloc/malloc-internal.h>. */
+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 };
+}
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef SUPPORT_BLOB_REPEAT_H
+#define SUPPORT_BLOB_REPEAT_H
+
+#include <stdbool.h>
+#include <stddef.h>
+
+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 */
/* 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 */
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef SUPPORT_DESCRIPTORS_H
+#define SUPPORT_DESCRIPTORS_H
+
+#include <stdio.h>
+
+/* 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 */
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. */
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);
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);
}
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <xunistd.h>
+
+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 <malloc/dynarray-skeleton.c>
+
+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);
+}
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <string.h>
+#include <support/support.h>
+
+char *
+support_quote_string (const char *str)
+{
+ return support_quote_blob (str, strlen (str));
+}
__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);
+}
#include <string.h>
#include <sys/param.h>
#include <sys/resource.h>
+#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
/* 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))
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);
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);
}
--- /dev/null
+/* Tests for <support/blob_repeat.h>
+ 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <support/blob_repeat.h>
+#include <support/check.h>
+
+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 <support/test-driver.c>
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/capture_subprocess.h>
+#include <support/check.h>
+#include <support/descriptors.h>
+#include <support/support.h>
+#include <support/xunistd.h>
+
+/* 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 <support/test-driver.c>
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <support/check.h>
+#include <support/support.h>
+#include <string.h>
+#include <stdlib.h>
+
+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 <support/test-driver.c>
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <support/xthread.h>
+
+void
+xpthread_rwlock_destroy (pthread_rwlock_t *rwlock)
+{
+ xpthread_check_return ("pthread_rwlock_destroy",
+ pthread_rwlock_destroy (rwlock));
+}
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
*reloc_addr = value;
}
else
- __libc_fatal ("unexpected reloc type in static binary");
+ __libc_fatal ("Unexpected reloc type in static binary.\n");
}
#endif
ldouble: 2
Function: "cos":
+double: 1
float: 1
+idouble: 1
ifloat: 1
ildouble: 1
ldouble: 1
ldouble: 1
Function: "pow":
+double: 1
float: 1
+idouble: 1
ifloat: 1
ildouble: 2
ldouble: 2
ldouble: 2
Function: "sin":
+double: 1
float: 1
+idouble: 1
ifloat: 1
ildouble: 1
ldouble: 1
ldouble: 3
Function: "sincos":
+double: 1
float: 1
+idouble: 1
ifloat: 1
ildouble: 1
ldouble: 1
*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 */
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
{
return self->thread_specifics[key];
}
strong_alias (__pthread_getspecific, pthread_getspecific);
+hidden_def (__pthread_getspecific)
return 0;
}
strong_alias (__pthread_setspecific, pthread_setspecific);
+hidden_def (__pthread_setspecific)
#if IS_IN (libpthread)
hidden_proto (__pthread_key_create)
+hidden_proto (__pthread_getspecific)
+hidden_proto (__pthread_setspecific)
hidden_proto (_pthread_mutex_init)
#endif
+++ /dev/null
-/* 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
- <http://www.gnu.org/licenses/>. */
-
-
-#define LINKAGE static inline
-#define _dl_cet_check cet_check
-#include <sysdeps/x86/dl-cet.c>
-#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
*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 */
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)
{
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))
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;
NULL
*/
- .text
- .globl _start
- .type _start,@function
-_start:
+#include <sysdep.h>
+
+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
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. */
.section .text
-GLOBAL_LIBM_ENTRY(__exp2f)
+WEAK_LIBM_ENTRY(exp2f)
{.mfi
}
;;
-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
.section .text
-GLOBAL_LIBM_ENTRY(__log2f)
+WEAK_LIBM_ENTRY(log2f)
{ .mfi
alloc r32=ar.pfs,1,4,4,0
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
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
}
;;
-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
#undef fdivl
#include <math-narrow.h>
+#include <libc-diag.h>
+
+/* 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 <soft-fp.h>
#include <single.h>
#include <double.h>
CHECK_NARROW_DIV (ret, x, y);
return ret;
}
+DIAG_POP_NEEDS_COMMENT;
+
libm_alias_float_double (div)
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
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
__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
{
}
/* Run the handlers registered for the parent. */
- __run_fork_handlers (atfork_run_parent);
+ __run_fork_handlers (atfork_run_parent, multiple_threads);
}
return pid;
- 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),
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 */
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;
#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))
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;
# 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; \
/* 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) = \
+ 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 \
*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 */
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
#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)
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)
#endif
}
else
- __libc_fatal ("unexpected reloc type in static binary");
+ __libc_fatal ("Unexpected reloc type in static binary.\n");
}
#endif /* dl-irel.h */
#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
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)
#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)
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)
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
*/
#define _SYSDEPS_SYSDEP_H 1
#include <bits/hwcap.h>
-#include <tls.h>
-#include <htm.h>
#define PPC_FEATURE_970 (PPC_FEATURE_POWER4 + PPC_FEATURE_HAS_ALTIVEC)
#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__ */
ldouble: 2
Function: "cos":
+double: 1
+idouble: 1
ildouble: 1
ldouble: 1
ldouble: 4
Function: Imaginary part of "ctan_towardzero":
-double: 1
+double: 2
float: 2
-idouble: 1
+idouble: 2
ifloat: 2
ildouble: 5
ldouble: 5
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
ldouble: 2
Function: "sin":
+double: 1
+idouble: 1
ildouble: 1
ldouble: 1
ldouble: 3
Function: "sincos":
+double: 1
+idouble: 1
ildouble: 1
ldouble: 1
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
__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. */
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
*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 */
};
#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
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 */
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 */
ifeq ($(subdir),dirent)
sysdep_routines += getdirentries getdirentries64
+tests-internal += tst-readdir64-compat
endif
ifeq ($(subdir),nis)
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__ \
(__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__ \
/* SIGPOLL. */
struct
{
- long int si_band; /* Band event for SIGPOLL. */
+ __SI_BAND_TYPE si_band; /* Band event for SIGPOLL. */
int si_fd;
} _sigpoll;
# include <shlib-compat.h>
# if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2)
-# include <olddirent.h>
+# include <olddirent.h>
+# include <unistd.h>
-/* 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;
{
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;
return 0;
#else
struct ifreq ifr;
- int fd = __opensock ();
-
- if (fd < 0)
- return 0;
-
if (strlen (ifname) >= IFNAMSIZ)
{
__set_errno (ENODEV);
}
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;
#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
-#ifndef _KERNEL_SIGACTION_H
-# define _KERNEL_SIGACTION_H
-
-#include <signal.h>
-
-#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 <sysdeps/unix/sysv/linux/kernel_sigaction.h>
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);
}
/* NIOS2 uses the generic Linux UAPI but defines SA_RESTORER. */
#define SA_RESTORER 0x04000000
-#include <sysdeps/unix/sysv/linux/kernel_sigaction.h>
#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 <sysdeps/unix/sysv/linux/kernel_sigaction.h>
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. */
}
/* 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; \
+ } \
}
/* powerpc kernel sigaction is similar to generic Linux UAPI one,
but the architecture also defines SA_RESTORER. */
#define SA_RESTORER 0x04000000
-#include <sysdeps/unix/sysv/linux/kernel_sigaction.h>
#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 <sysdeps/unix/sysv/linux/kernel_sigaction.h>
+++ /dev/null
-/* 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
- <http://www.gnu.org/licenses/>. */
-
-/* __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
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" \
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" \
#include <sysdep.h>
ENTRY (syscall)
- ABORT_TRANSACTION
mr r0,r3
mr r3,r4
mr r4,r5
# 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:
#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:
# 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:
#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:
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. */
#include <stdlib.h>
#include <atomic.h>
#include <sys/cachectl.h>
-#include <asm/syscalls.h>
+#if __has_include__ (<asm/syscalls.h>)
+# include <asm/syscalls.h>
+#else
+# include <asm/unistd.h>
+#endif
typedef int (*func_type) (void *, void *, unsigned long int);
#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
/* 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; \
+ } \
}
/* SH uses the generic Linux UAPI but defines SA_RESTORER. */
#define SA_RESTORER 0x04000000
-#include <sysdeps/unix/sysv/linux/kernel_sigaction.h>
#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 <sysdeps/unix/sysv/linux/kernel_sigaction.h>
#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;
/* 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 <sysdeps/unix/sysv/linux/kernel_sigaction.h>
-
-#define SET_SA_RESTORER(kact, act) \
- (kact)->sa_restorer = NULL
-#define RESET_SA_RESTORER(act, kact) \
- (act)->sa_restorer = (kact)->sa_restorer
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
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)
# 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
io_cancel
io_destroy
io_getevents
+io_pgetevents
io_setup
io_submit
ioctl
request_key
restart_syscall
rmdir
+rseq
rt_sigaction
rt_sigpending
rt_sigprocmask
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <dirent.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <shlib-compat.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <support/check.h>
+
+/* Copied from <olddirent.h>. */
+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 <support/test-driver.c>
/* 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; \
+ } \
}
#include <signal.h>
#define SA_RESTORER 0x04000000
-#include <kernel_sigaction.h>
extern void restore_rt (void) asm ("__restore_rt") attribute_hidden;
#define RESET_SA_RESTORER(act, kact) \
(act)->sa_restorer = (kact)->sa_restorer
+#include <kernel_sigaction.h>
+
#include <sysdeps/unix/sysv/linux/sigaction.c>
/* NOTE: Please think twice before making any changes to the bits of
| 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)
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. */
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. */
&& 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;
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)
{
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;
}
+ 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
}
/* 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;
*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 */
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
.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
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)
movq %r11, %r10
andq $-64, %r10
cmpq %r10, %rdi
- jge L(mt32)
+ jae L(mt32)
L(A64main):
movdqu (%rdi,%rsi), %xmm0
movq %r11, %r10
andq $-32, %r10
cmpq %r10, %rdi
- jge L(mt16)
+ jae L(mt16)
L(A32main):
movdqu (%rdi,%rsi), %xmm0
movq %r11, %r10
andq $-32, %r10
cmpq %r10, %rdi
- jge L(mt16)
+ jae L(mt16)
testq $16, %rdi
jz L(ATR32)
movq %r11, %r10
andq $-32, %r10
cmpq %r10, %rdi
- jge L(mt16)
+ jae L(mt16)
L(ATR32res):
movdqa (%rdi,%rsi), %xmm0
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
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. */
.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. */
.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
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
.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
.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
.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
.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
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):
# 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
# 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
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. */
# endif
jb L(more_8x_vec_backward)
1:
- movq %rdx, %rcx
+ mov %RDX_LP, %RCX_LP
rep movsb
L(nop):
ret
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
.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
.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)
#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))
#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)
# 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
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)
# 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)
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
#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
.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
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)
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
* 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
#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
# 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
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#define TEST_MAIN
+#include <string/test-string.h>
+
+/* 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;
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#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 <wchar.h>
+# 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 <support/test-driver.c>
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#define TEST_MAIN
+#ifdef WIDE
+# define TEST_NAME "wmemcmp"
+#else
+# define TEST_NAME "memcmp"
+#endif
+
+#include "test-size_t.h"
+
+#ifdef WIDE
+# include <inttypes.h>
+# include <wchar.h>
+
+# 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 <support/test-driver.c>
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#define TEST_MAIN
+#ifdef WIDE
+# define TEST_NAME "wmemcmp"
+#else
+# define TEST_NAME "memcmp"
+#endif
+
+#include "test-size_t.h"
+
+#ifdef WIDE
+# include <inttypes.h>
+# include <wchar.h>
+
+# 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 <support/test-driver.c>
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#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 <support/test-driver.c>
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#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 <support/test-driver.c>
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef WIDE
+# define TEST_NAME "wmemset"
+#else
+# define TEST_NAME "memset"
+#endif /* WIDE */
+
+#include "test-size_t.h"
+
+#ifdef WIDE
+# include <wchar.h>
+# 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 <support/test-driver.c>
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#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 <support/test-driver.c>
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef WIDE
+# define TEST_NAME "wcsncmp"
+#else
+# define TEST_NAME "strncmp"
+#endif
+
+#include "test-size_t.h"
+
+#ifdef WIDE
+# include <wchar.h>
+
+# 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 <support/test-driver.c>
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#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 <support/test-driver.c>
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef WIDE
+# define TEST_NAME "wcsnlen"
+#else
+# define TEST_NAME "strnlen"
+#endif /* WIDE */
+
+#include "test-size_t.h"
+
+#ifdef WIDE
+# include <wchar.h>
+# 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 <support/test-driver.c>
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#define WIDE 1
+#include "tst-size_t-strncmp.c"
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#define WIDE 1
+#include "tst-size_t-strnlen.c"
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#define WIDE 1
+#include "tst-size_t-memchr.c"
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#define WIDE 1
+#include "tst-size_t-memcmp.c"
--- /dev/null
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#define WIDE 1
+#include "tst-size_t-memset.c"
/* 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