GIT update of https://sourceware.org/git/glibc.git/release/2.29/master from glibc-2.29
GIT update of https://sourceware.org/git/glibc.git/release/2.29/master from glibc-2.29
Gbp-Pq: Name git-updates.diff
+2019-07-24 Florian Weimer <fweimer@redhat.com>
+
+ [BZ #24532]
+ Linux: Use in-tree copy of SO_ constants for !__USE_MISC.
+ * sysdeps/unix/sysv/linux/Makefile [$(subdir) == socket]
+ (sysdep_headers): Add bits/socket-constants.h.
+ (tests-special): Add tst-socket-consts.out.
+ (tst-socket-consts.out): New target.
+ * sysdeps/unix/sysv/linux/bits/socket.h: Remove macro tracking
+ around <asm/unistd.h>.
+ [__USE_MISC]: Include <bits/types/time_t.h> before <asm/socket.h>.
+ [!__USE_MISC]: Include <sys/socket-constants.h> instead of
+ <asm/socket.h>.
+ * sysdeps/unix/sysv/linux/bits/tst-socket-consts.py: New file.
+ * sysdeps/unix/sysv/linux/bits/socket-constants.h: Likewise.
+ * sysdeps/unix/sysv/linux/alpha/bits/socket-constants.h: Likewise.
+ * sysdeps/unix/sysv/linux/hppa/bits/socket-constants.h: Likewise.
+ * sysdeps/unix/sysv/linux/mips/bits/socket-constants.h: Likewise.
+ * sysdeps/unix/sysv/linux/powerpc/bits/socket-constants.h:
+ Likewise.
+ * sysdeps/unix/sysv/linux/sparc/bits/socket-constants.h: Likewise.
+
+2019-08-15 Florian Weimer <fweimer@redhat.com>
+
+ * malloc/Makefile (tests): Only add tst-mxfast for
+ $(have-tunables).
+ * malloc/tst-mxfast.c: Fix copyright year.
+ (do_test): Fix GNU style issues. Use TEST_COMPARE instead of
+ assert for checks.
+
+2019-08-09 DJ Delorie <dj@redhat.com>
+
+ * elf/dl-tunables.list: Add glibc.malloc.mxfast.
+ * manual/tunables.texi: Document it.
+ * malloc/malloc.c (do_set_mxfast): New.
+ (__libc_mallopt): Call it.
+ * malloc/arena.c: Add mxfast tunable.
+ * malloc/tst-mxfast.c: New.
+ * malloc/Makefile: Add it.
+
+2019-08-08 Niklas Hambüchen <mail@nh2.me>
+ Carlos O'Donell <carlos@redhat.com>
+
+ [BZ #24026]
+ * malloc/malloc.c (__malloc_info): Account for top chunk.
+
+2019-08-01 Florian Weimer <fweimer@redhat.com>
+
+ [BZ #24867]
+ * malloc/malloc.c (__malloc_info): Remove unwanted leading
+ whitespace.
+
+2019-05-17 Wilco Dijkstra <wdijkstr@arm.com>
+
+ * malloc/malloc.c (MAX_TCACHE_COUNT): Increase to UINT16_MAX.
+ (tcache_put): Remove redundant assert.
+ (tcache_get): Remove redundant asserts.
+ (__libc_malloc): Check tcache count is not zero.
+ * manual/tunables.texi (glibc.malloc.tcache_count): Update maximum.
+
+2019-02-04 Joseph Myers <joseph@codesourcery.com>
+
+ * malloc/malloc.c (tcache_get): Compare tcache->counts[tc_idx]
+ with 0, not tcache->entries[tc_idx].
+
+2019-02-06 Stefan Liebler <stli@linux.ibm.com>
+
+ [BZ #23403]
+ * nptl/allocatestack.c (allocate_stack): Align pointer pd for
+ TLS_TCB_AT_TP tls variant.
+ * nptl/tst-tls1.c: Migrate to support/test-driver.c.
+ Add alignment checks.
+ * support/Makefile (libsupport-routines): Add xposix_memalign and
+ xpthread_setstack.
+ * support/support.h: Add xposix_memalign.
+ * support/xthread.h: Add xpthread_attr_setstack.
+ * support/xposix_memalign.c: New File.
+ * support/xpthread_attr_setstack.c: Likewise.
+
+2019-06-18 Florian Weimer <fweimer@redhat.com>
+
+ [BZ #24323]
+ * include/elf.h (DT_1_SUPPORTED_MASK): Include DF_1_PIE.
+ * elf/dl-load.c (_dl_map_object_from_fd): Check for DF_1_PIE and
+ fail when called from dlopen.
+ * elf/Makefile [have-fpie && build-shared] (tests): Add
+ tst-dlopen-pie.
+ (tst-dlopen-pie): Link with -ldl.
+ (tst-dlopen-pie.out): Add run-time dependency on tst-pie1.
+ * elf/tst-dlopen-pie.c (do_test): New file.
+
+2019-07-10 DJ Delorie <dj@redhat.com>
+ Sergei Trofimovich <slyfox@inbox.ru>
+
+ [BZ #24696]
+ [BZ #24695]
+ * nss/nss_db/db-open.c (internal_endent): Protect against NULL
+ mappings.
+ * nss/tst-nss-db-endgrent.c: New.
+ * nss/tst-nss-db-endgrent.root: New.
+ * nss/tst-nss-db-endpwent.c: New.
+ * nss/tst-nss-db-endpwent.root: New.
+ * nss/Makefile: Add new tests.
+ * support/links-dso-program-c.c: Add selinux dependency.
+ * support/links-dso-program.cc: Add selinux dependency.
+ * support/Makefile: Build those with -lselinux if enabled.
+
+2019-05-14 Adhemerval Zanella <adhemerval.zanella@linaro.org>
+
+ * support/Makefile (CFLAGS-support_paths.c): Add -DBINDIR_PATH.
+ * support/support.h (support_bindir_prefix): New variable.
+ * support/support_paths.c [BINDIR_PATH] (support_bindir_prefix):
+
+ * config.make.in (bindir): New variable.
+
+2019-07-01 H.J. Lu <hongjiu.lu@intel.com>
+
+ [BZ #24259]
+ * elf/dl-open.c (dl_open_worker): Call _dl_open_check after
+ relocation.
+ * sysdeps/x86/Makefile (tests): Add tst-cet-legacy-5a,
+ tst-cet-legacy-5b, tst-cet-legacy-6a and tst-cet-legacy-6b.
+ (modules-names): Add tst-cet-legacy-mod-5a, tst-cet-legacy-mod-5b,
+ tst-cet-legacy-mod-5c, tst-cet-legacy-mod-6a, tst-cet-legacy-mod-6b
+ and tst-cet-legacy-mod-6c.
+ (CFLAGS-tst-cet-legacy-5a.c): New.
+ (CFLAGS-tst-cet-legacy-5b.c): Likewise.
+ (CFLAGS-tst-cet-legacy-mod-5a.c): Likewise.
+ (CFLAGS-tst-cet-legacy-mod-5b.c): Likewise.
+ (CFLAGS-tst-cet-legacy-mod-5c.c): Likewise.
+ (CFLAGS-tst-cet-legacy-6a.c): Likewise.
+ (CFLAGS-tst-cet-legacy-6b.c): Likewise.
+ (CFLAGS-tst-cet-legacy-mod-6a.c): Likewise.
+ (CFLAGS-tst-cet-legacy-mod-6b.c): Likewise.
+ (CFLAGS-tst-cet-legacy-mod-6c.c): Likewise.
+ ($(objpfx)tst-cet-legacy-5a): Likewise.
+ ($(objpfx)tst-cet-legacy-5a.out): Likewise.
+ ($(objpfx)tst-cet-legacy-mod-5a.so): Likewise.
+ ($(objpfx)tst-cet-legacy-mod-5b.so): Likewise.
+ ($(objpfx)tst-cet-legacy-5b): Likewise.
+ ($(objpfx)tst-cet-legacy-5b.out): Likewise.
+ (tst-cet-legacy-5b-ENV): Likewise.
+ ($(objpfx)tst-cet-legacy-6a): Likewise.
+ ($(objpfx)tst-cet-legacy-6a.out): Likewise.
+ ($(objpfx)tst-cet-legacy-mod-6a.so): Likewise.
+ ($(objpfx)tst-cet-legacy-mod-6b.so): Likewise.
+ ($(objpfx)tst-cet-legacy-6b): Likewise.
+ ($(objpfx)tst-cet-legacy-6b.out): Likewise.
+ (tst-cet-legacy-6b-ENV): Likewise.
+ * sysdeps/x86/tst-cet-legacy-5.c: New file.
+ * sysdeps/x86/tst-cet-legacy-5a.c: Likewise.
+ * sysdeps/x86/tst-cet-legacy-5b.c: Likewise.
+ * sysdeps/x86/tst-cet-legacy-6.c: Likewise.
+ * sysdeps/x86/tst-cet-legacy-6a.c: Likewise.
+ * sysdeps/x86/tst-cet-legacy-6b.c: Likewise.
+ * sysdeps/x86/tst-cet-legacy-mod-5.c: Likewise.
+ * sysdeps/x86/tst-cet-legacy-mod-5a.c: Likewise.
+ * sysdeps/x86/tst-cet-legacy-mod-5b.c: Likewise.
+ * sysdeps/x86/tst-cet-legacy-mod-5c.c: Likewise.
+ * sysdeps/x86/tst-cet-legacy-mod-6.c: Likewise.
+ * sysdeps/x86/tst-cet-legacy-mod-6a.c: Likewise.
+ * sysdeps/x86/tst-cet-legacy-mod-6b.c: Likewise.
+ * sysdeps/x86/tst-cet-legacy-mod-6c.c: Likewise.
+
+2019-09-20 Joseph Myers <joseph@codesourcery.com>
+
+ * sysdeps/unix/sysv/linux/riscv/vfork.S: Do not include
+ <linux/sched.h>.
+ (CLONE_VM): New macro.
+ (CLONE_VFORK): Likewise.
+
+2019-09-14 Aurelien Jarno <aurelien@aurel32.net>
+
+ [BZ #24986]
+ * sysdeps/unix/alpha/getegid.S: Move to ...
+ * sysdeps/unix/sysv/linux/alpha/getegid.S: ... here.
+ * sysdeps/unix/alpha/geteuid.S: Move to ...
+ * sysdeps/unix/sysv/linux/alpha/geteuid.S: ... here.
+ * sysdeps/unix/alpha/getppid.S: Move to ...
+ * sysdeps/unix/sysv/linux/alpha/getppid.S: ... here
+
+2019-09-13 Wilco Dijkstra <wdijkstr@arm.com>
+
+ * string/memmem.c (__memmem): Rewrite to improve performance.
+
+2019-06-12 Wilco Dijkstra <wdijkstr@arm.com>
+
+ * string/str-two-way.h (two_way_short_needle): Add inline to avoid
+ warning.
+ (two_way_long_needle): Block inlining.
+ * string/strstr.c (strstr2): Add new function.
+ (strstr3): Likewise.
+ (STRSTR): Completely rewrite strstr to improve performance.
+
+2019-09-03 Aurelien Jarno <aurelien@aurel32.net>
+
+ * sysdeps/alpha/fpu/libm-test-ulps: Regenerated using GCC 9.2.
+
+2019-08-18 Adhemerval Zanella <adhemerval.zanella@linaro.org>
+
+ * sysdeps/hppa/fpu/libm-test-ulps: Update.
+
+2019-08-15 Richard Henderson <rth@twiddle.net>
+
+ * sysdeps/unix/sysv/linux/alpha/kernel-features.h (__NR_shmat):
+ Do not redefine.
+ * sysdeps/unix/sysv/linux/alpha/sysdep.h (__NR_osf_shmat):
+ Do not redefine.
+
+2019-07-15 Adhemerval Zanella <adhemerval.zanella@linaro.org>
+
+ [BZ #24699]
+ * posix/tst-mmap-offset.c: Mention BZ #24699.
+ (do_test_bz21270): Rename to do_test_large_offset and use
+ mmap64_maximum_offset to check for maximum expected offset value.
+ * sysdeps/generic/mmap_info.h: New file.
+ * sysdeps/unix/sysv/linux/mips/mmap_info.h: Likewise.
+ * sysdeps/unix/sysv/linux/mmap64.c (MMAP_OFF_HIGH_MASK): Define iff
+ __NR_mmap2 is used.
+
+2019-07-12 Szabolcs Nagy <szabolcs.nagy@arm.com>
+
+ * sysdeps/aarch64/dl-machine.h (elf_machine_lazy_rel): Check
+ STO_AARCH64_VARIANT_PCS and bind such symbols at load time.
+
+2019-06-13 Szabolcs Nagy <szabolcs.nagy@arm.com>
+
+ * elf/elf.h (STO_AARCH64_VARIANT_PCS): Define.
+ (DT_AARCH64_VARIANT_PCS): Define.
+
+2019-06-28 Florian Weimer <fweimer@redhat.com>
+
+ [BZ #24744]
+ io: Remove the copy_file_range emulation.
+ * sysdeps/unix/sysv/linux/copy_file_range.c (copy_file_range): Do
+ not define and call copy_file_range_compat.
+ * io/Makefile (tests-static, tests-internal): Do not add
+ tst-copy_file_range-compat.
+ * io/copy_file_range-compat.c: Remove file.
+ * io/copy_file_range.c (copy_file_range): Define as stub.
+ * io/tst-copy_file_range-compat.c: Remove file.
+ * io/tst-copy_file_range.c (xdevfile): Remove variable.
+ (typical_sizes): Update comment. Remove 16K sizes.
+ (maximum_offset, maximum_offset_errno, maximum_offset_hard_limit):
+ Remove variables.
+ (find_maximum_offset, pipe_as_source, pipe_as_destination)
+ (delayed_write_failure_beginning, delayed_write_failure_end)
+ (cross_device_failure, enospc_failure_1, enospc_failure)
+ (oappend_failure): Remove functions.
+ (tests): Adjust test case list.
+ (do_test): Remove file system search code. Check for ENOSYS from
+ copy_file_range. Do not free xdevfile.
+ * manual/llio.texi (Copying File Data): Document ENOSYS error from
+ copy_file_range. Do not document the EXDEV error, which future
+ kernels may not report. Update the wording to reflect that
+ further errors are possible.
+ * sysdeps/unix/sysv/linux/alpha/kernel-features.h
+ [__LINUX_KERNEL_VERSION < 0x040D00] (__ASSUME_COPY_FILE_RANGE): Do
+ not undefine.
+ * sysdeps/unix/sysv/linux/arm/kernel-features.h
+ [__LINUX_KERNEL_VERSION < 0x040700] (__ASSUME_COPY_FILE_RANGE):
+ Likewise.
+ * sysdeps/unix/sysv/linux/kernel-features.h
+ [__LINUX_KERNEL_VERSION >= 0x040500] (__ASSUME_COPY_FILE_RANGE):
+ Remove definition.
+ * sysdeps/unix/sysv/linux/microblaze/kernel-features.h
+ [__LINUX_KERNEL_VERSION < 0x040A00] (__ASSUME_COPY_FILE_RANGE): Do
+ not undefine.
+ * sysdeps/unix/sysv/linux/sh/kernel-features.h
+ [__LINUX_KERNEL_VERSION < 0x040800] (__ASSUME_COPY_FILE_RANGE):
+ Likewise.
+
+2019-06-20 Dmitry V. Levin <ldv@altlinux.org>
+ Florian Weimer <fweimer@redhat.com>
+
+ [BZ #24228]
+ * libio/genops.c (_IO_unbuffer_all)
+ [SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)]: Do not attempt to free wide
+ buffers and access _IO_FILE_complete members of legacy libio streams.
+ * libio/tst-bz24228.c: New file.
+ * libio/tst-bz24228.map: Likewise.
+ * libio/Makefile [build-shared] (tests): Add tst-bz24228.
+ [build-shared] (generated): Add tst-bz24228.mtrace and
+ tst-bz24228.check.
+ [run-built-tests && build-shared] (tests-special): Add
+ $(objpfx)tst-bz24228-mem.out.
+ (LDFLAGS-tst-bz24228, tst-bz24228-ENV): New variables.
+ ($(objpfx)tst-bz24228-mem.out): New rule.
+
+2019-03-13 Zack Weinberg <zackw@panix.com>
+
+ * scripts/check-obsolete-constructs.py: New test script.
+ * scripts/check-installed-headers.sh: Remove tests for
+ obsolete typedefs, superseded by check-obsolete-constructs.py.
+ * Rules: Run scripts/check-obsolete-constructs.py over $(headers)
+ as a special test. Update commentary.
+ * posix/bits/types.h (__SQUAD_TYPE, __S64_TYPE): Define as __int64_t.
+ (__UQUAD_TYPE, __U64_TYPE): Define as __uint64_t.
+ Update commentary.
+ * posix/sys/types.h (__u_intN_t): Remove.
+ (u_int8_t): Typedef using __uint8_t.
+ (u_int16_t): Typedef using __uint16_t.
+ (u_int32_t): Typedef using __uint32_t.
+ (u_int64_t): Typedef using __uint64_t.
+
+2019-04-18 Adhemerval Zanella <adhemerval.zanella@linaro.org>
+
+ * malloc/tst-memalign.c (do_test): Disable
+ -Walloc-size-larger-than= around tests of malloc with negative
+ sizes.
+ * malloc/tst-malloc-too-large.c (do_test): Likewise.
+
+2019-05-22 Wilco Dijkstra <wdijkstr@arm.com>
+
+ [BZ #24531]
+ * malloc/malloc.c (MAX_TCACHE_COUNT): New define.
+ (do_set_tcache_count): Only update if count is small enough.
+ * manual/tunables.texi (glibc.malloc.tcache_count): Document max value.
+
+2019-05-15 Mark Wielaard <mark@klomp.org>
+
+ [BZ#24476]
+ * dlfcn/dlerror.c (__dlerror_main_freeres): Guard using
+ __libc_once_get (once) and static_buf == NULL.
+ (__dlerror): Check we have a valid key, set result to static_buf
+ otherwise.
+
+2019-05-15 Andreas Schwab <schwab@suse.de>
+
+ [BZ #20568]
+ * libio/wfileops.c (_IO_wfile_sync): Correct last argument to
+ __codecvt_do_length.
+ * libio/Makefile (tests): Add tst-wfile-sync.
+ ($(objpfx)tst-wfile-sync.out): Depend on $(gen-locales).
+ * libio/tst-wfile-sync.c: New file.
+ * libio/tst-wfile-sync.input: New file.
+
+2019-04-23 Adhemerval Zanella <adhemerval.zanella@linaro.org>
+
+ [BZ #18035]
+ * elf/Makefile (tests-container): Add tst-pldd.
+ * 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.
+ * elf/tst-pldd.c: New file.
+
+2019-04-17 Adhemerval Zanella <adhemerval.zanella@linaro.org>
+
+ * support/Makefile (libsupport-routines): Add support_subprocess,
+ xposix_spawn, xposix_spawn_file_actions_addclose, and
+ xposix_spawn_file_actions_adddup2.
+ (tst-support_capture_subprocess-ARGS): New rule.
+ * support/capture_subprocess.h (support_capture_subprogram): New
+ prototype.
+ * support/support_capture_subprocess.c (support_capture_subprocess):
+ Refactor to use support_subprocess and support_capture_poll.
+ (support_capture_subprogram): New function.
+ * support/tst-support_capture_subprocess.c (write_mode_to_str,
+ str_to_write_mode, test_common, parse_int, handle_restart,
+ do_subprocess, do_subprogram, do_multiple_tests): New functions.
+ (do_test): Add support_capture_subprogram tests.
+ * support/subprocess.h: New file.
+ * support/support_subprocess.c: Likewise.
+ * support/xposix_spawn.c: Likewise.
+ * support/xposix_spawn_file_actions_addclose.c: Likewise.
+ * support/xposix_spawn_file_actions_adddup2.c: Likewise.
+ * support/xspawn.h: Likewise.
+
+2019-04-09 Carlos O'Donell <carlos@redhat.com>
+ Kwok Cheung Yeung <kcy@codesourcery.com>
+
+ [BZ #16573]
+ * malloc/mtrace.c: Define prototypes for all hooks.
+ (set_default_hooks): New function.
+ (set_trace_hooks): Likewise.
+ (save_default_hooks): Likewise.
+ (tr_freehook): Use new s*_hooks functions.
+ (tr_mallochook): Likewise.
+ (tr_reallochook): Likewise.
+ (tr_memalignhook): Likewise.
+ (mtrace): Likewise.
+ (muntrace): Likewise.
+
+2019-04-02 TAMUKI Shoichi <tamuki@linet.gr.jp>
+
+ [BZ #22964]
+ * localedata/locales/ja_JP (LC_TIME): Add entry for the new Japanese
+ era.
+
+2019-03-02 TAMUKI Shoichi <tamuki@linet.gr.jp>
+
+ [BZ #24162]
+ * localedata/locales/ja_JP (LC_TIME): Change the offset for Taisho
+ gan-nen from 2 to 1. Problem reported by Morimitsu, Junji.
+
+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.
+
+2019-03-13 Stefan Liebler <stli@linux.ibm.com>
+
+ * elf/dl-sysdep.c (_dl_show_auxv): Remove condition and always
+ call _dl_procinfo.
+ * sysdeps/unix/sysv/linux/s390/dl-procinfo.h (_dl_procinfo):
+ Ignore types other than AT_HWCAP.
+ * sysdeps/sparc/dl-procinfo.h (_dl_procinfo): Likewise.
+ * sysdeps/unix/sysv/linux/i386/dl-procinfo.h (_dl_procinfo):
+ Likewise.
+ * sysdeps/powerpc/dl-procinfo.h (_dl_procinfo): Adjust comment
+ in the case of falling back to generic output mechanism.
+ * sysdeps/unix/sysv/linux/arm/dl-procinfo.h (_dl_procinfo):
+ Likewise.
+
+2019-02-15 Florian Weimer <fweimer@redhat.com>
+
+ [BZ #24211]
+ * nptl/pthread_join_common.c (__pthread_timedjoin_ex): Do not read
+ pd->result after the thread descriptor has been freed.
+
+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-05 Florian Weimer <fweimer@redhat.com>
+
+ [BZ #24164]
+ arm: Use "nr" constraint for Systemtap probes, to avoid the
+ compiler using memory operands for constants, due to the "o"
+ alternative in the default "nor" constraint.
+ * include/stap-probe.h [USE_STAP_PROBE]: Include
+ <stap-probe-machine.h>
+ * sysdeps/generic/stap-probe-machine.h: New file.
+ * sysdeps/arm/stap-probe-machine.h: Likewise.
+
+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-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-01-31 Siddhesh Poyarekar <siddhesh@sourceware.org>
* version.h (RELEASE): Set to "stable".
Please send GNU C library bug reports via <https://sourceware.org/bugzilla/>
using `glibc' in the "product" field.
+\f
+Version 2.29.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:
+
+* The copy_file_range function fails with ENOSYS if the kernel does not
+ support the system call of the same name. Previously, user space
+ emulation was performed, but its behavior did not match the kernel
+ behavior, which was deemed too confusing. Applications which use the
+ copy_file_range function will have to be run on kernels which implement
+ the copy_file_range system call. Support for most architectures was added
+ in version 4.5 of the mainline Linux kernel.
+
+The following bugs are resolved with this release:
+
+ [16573] malloc: Set and reset all hooks for tracing
+ [18035] Fix pldd hang
+ [20568] Fix crash in _IO_wfile_sync
+ [24155] x32 memcmp can treat positive length as 0 (if sign bit in RDX is set) (CVE-2019-7309)
+ [24164] Systemtap probes need to use "nr" constraint on 32-bit Arm
+ [24161] __run_fork_handlers self-deadlocks in malloc/tst-mallocfork2
+ [24211] Use-after-free in Systemtap probe in pthread_join
+ [24228] old x86 applications that use legacy libio crash on exit
+ [24476] dlfcn: Guard __dlerror_main_freeres with __libc_once_get (once)
+ [24744] io: Remove the copy_file_range emulation
+ [24986] alpha: new getegid, geteuid and getppid syscalls used
+ unconditionally
+ [25203] libio: Disable vtable validation for pre-2.1 interposed handles
+ [25204] Ignore LD_PREFER_MAP_32BIT_EXEC for SUID programs
+ [25225] ld.so fails to link on x86 if GCC defaults to -fcf-protection
+ [25232] No const correctness for strchr et al. for Clang++
+
+Security related changes:
+
+ 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-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.
+
+ CVE-2019-19126: ld.so failed to ignore the LD_PREFER_MAP_32BIT_EXEC
+ environment variable during program execution after a security
+ transition, allowing local attackers to restrict the possible mapping
+ addresses for loaded libraries and thus bypass ASLR for a setuid
+ program. Reported by Marcin Kościelnicki.
+
\f
Version 2.29
common-generated += dummy.o dummy.c
ifneq "$(headers)" ""
-# Special test of all the installed headers in this directory.
+# Test that all of the headers installed by this directory can be compiled
+# in isolation.
tests-special += $(objpfx)check-installed-headers-c.out
libof-check-installed-headers-c := testsuite
$(objpfx)check-installed-headers-c.out: \
$(evaluate-test)
ifneq "$(CXX)" ""
+# If a C++ compiler is available, also test that they can be compiled
+# in isolation as C++.
tests-special += $(objpfx)check-installed-headers-cxx.out
libof-check-installed-headers-cxx := testsuite
$(objpfx)check-installed-headers-cxx.out: \
fi
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+#ifndef __CET__
+#error no CET compiler support
+#endif
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ libc_cv_compiler_default_cet=yes
+else
+ libc_cv_compiler_default_cet=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
# Check whether --enable-cet was given.
if test "${enable_cet+set}" = set; then :
enableval=$enable_cet; enable_cet=$enableval
else
- enable_cet=no
+ enable_cet=$libc_cv_compiler_default_cet
fi
[build_mathvec=$enableval],
[build_mathvec=notset])
+AC_TRY_COMPILE([], [
+#ifndef __CET__
+# error no CET compiler support
+#endif],
+ [libc_cv_compiler_default_cet=yes],
+ [libc_cv_compiler_default_cet=no])
+
AC_ARG_ENABLE([cet],
AC_HELP_STRING([--enable-cet],
[enable Intel Control-flow Enforcement Technology (CET), x86 only]),
[enable_cet=$enableval],
- [enable_cet=no])
+ [enable_cet=$libc_cv_compiler_default_cet])
# We keep the original values in `$config_*' and never modify them, so we
# can write them unchanged into config.make. Everything else uses
__libc_once (once, init);
/* Get error string. */
- result = (struct dl_action_result *) __libc_getspecific (key);
- if (result == NULL)
- result = &last_result;
+ if (static_buf != NULL)
+ result = static_buf;
+ else
+ {
+ /* init () has been run and we don't use the static buffer.
+ So we have a valid key. */
+ result = (struct dl_action_result *) __libc_getspecific (key);
+ if (result == NULL)
+ result = &last_result;
+ }
/* Test whether we already returned the string. */
if (result->returned != 0)
void
__dlerror_main_freeres (void)
{
- void *mem;
/* Free the global memory if used. */
check_free (&last_result);
- /* Free the TSD memory if used. */
- mem = __libc_getspecific (key);
- if (mem != NULL)
- free_key_mem (mem);
+
+ if (__libc_once_get (once) && static_buf == NULL)
+ {
+ /* init () has been run and we don't use the static buffer.
+ So we have a valid key. */
+ void *mem;
+ /* Free the TSD memory if used. */
+ mem = __libc_getspecific (key);
+ if (mem != NULL)
+ free_key_mem (mem);
+ }
}
struct dlfcn_hook *_dlfcn_hook __attribute__((nocommon));
tst-tls3 tst-tls6 tst-tls7 tst-tls8 tst-dlmopen2 \
tst-ptrguard1 tst-stackguard1 tst-libc_dlvsym \
tst-create_format1
+tests-container += tst-pldd
ifeq ($(build-hardcoded-path-in-tests),yes)
tests += tst-dlopen-aout
tst-dlopen-aout-no-pie = yes
endif
ifeq (yesyes,$(have-fpie)$(build-shared))
modules-names += tst-piemod1
-tests += tst-pie1 tst-pie2
+tests += tst-pie1 tst-pie2 tst-dlopen-pie
tests-pie += tst-pie1 tst-pie2
ifeq (yes,$(have-protected-data))
tests += vismain
$(objpfx)tst-piemod1.so: $(libsupport)
$(objpfx)tst-pie1: $(objpfx)tst-piemod1.so
+$(objpfx)tst-dlopen-pie: $(libdl)
+$(objpfx)tst-dlopen-pie.out: $(objpfx)tst-pie1
ifeq (yes,$(build-shared))
# NB: Please keep cet-built-dso in sysdeps/x86/Makefile in sync with
goto call_lose;
}
+ /* dlopen of an executable is not valid because it is not possible
+ to perform proper relocations, handle static TLS, or run the
+ ELF constructors. For PIE, the check needs the dynamic
+ section, so there is another check below. */
if (__glibc_unlikely (type != ET_DYN)
&& __glibc_unlikely ((mode & __RTLD_OPENEXEC) == 0))
{
elf_get_dynamic_info (l, NULL);
/* Make sure we are not dlopen'ing an object that has the
- DF_1_NOOPEN flag set. */
- if (__glibc_unlikely (l->l_flags_1 & DF_1_NOOPEN)
- && (mode & __RTLD_DLOPEN))
+ DF_1_NOOPEN flag set, or a PIE object. */
+ if ((__glibc_unlikely (l->l_flags_1 & DF_1_NOOPEN)
+ && (mode & __RTLD_DLOPEN))
+ || (__glibc_unlikely (l->l_flags_1 & DF_1_PIE)
+ && __glibc_unlikely ((mode & __RTLD_OPENEXEC) == 0)))
{
/* We are not supposed to load this object. Free all resources. */
_dl_unmap_segments (l);
if (l->l_phdr_allocated)
free ((void *) l->l_phdr);
- errstring = N_("shared object cannot be dlopen()ed");
+ if (l->l_flags_1 & DF_1_PIE)
+ errstring
+ = N_("cannot dynamically load position-independent executable");
+ else
+ errstring = N_("shared object cannot be dlopen()ed");
goto call_lose;
}
_dl_debug_state ();
LIBC_PROBE (map_complete, 3, args->nsid, r, new);
- _dl_open_check (new);
-
/* Print scope information. */
if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SCOPES))
_dl_show_scope (new, 0);
_dl_relocate_object (l, l->l_scope, reloc_mode, 0);
}
+ /* NB: Workaround for [BZ #20839] which doesn't remove the NODELETE
+ object when _dl_open_check throws an exception. Move it after
+ relocation to avoid leaving the NODELETE object mapped without
+ relocation. */
+ _dl_open_check (new);
+
/* If the file is not loaded now as a dependency, add the search
list of the newly loaded object to the scope. */
bool any_tls = false;
assert (AT_NULL == 0);
assert (AT_IGNORE == 1);
- if (av->a_type == AT_HWCAP || av->a_type == AT_HWCAP2
- || AT_L1I_CACHEGEOMETRY || AT_L1D_CACHEGEOMETRY
- || AT_L2_CACHEGEOMETRY || AT_L3_CACHEGEOMETRY)
- {
- /* These are handled in a special way per platform. */
- if (_dl_procinfo (av->a_type, av->a_un.a_val) == 0)
- continue;
- }
+ /* Some entries are handled in a special way per platform. */
+ if (_dl_procinfo (av->a_type, av->a_un.a_val) == 0)
+ continue;
if (idx < sizeof (auxvars) / sizeof (auxvars[0])
&& auxvars[idx].form != unknown)
tcache_unsorted_limit {
type: SIZE_T
}
+ mxfast {
+ type: SIZE_T
+ minval: 0
+ security_level: SXID_IGNORE
+ }
}
cpu {
hwcap_mask {
#define R_AARCH64_TLSDESC 1031 /* TLS Descriptor. */
#define R_AARCH64_IRELATIVE 1032 /* STT_GNU_IFUNC relocation. */
+/* AArch64 specific values for the Dyn d_tag field. */
+#define DT_AARCH64_VARIANT_PCS (DT_LOPROC + 5)
+#define DT_AARCH64_NUM 6
+
+/* AArch64 specific values for the st_other field. */
+#define STO_AARCH64_VARIANT_PCS 0x80
+
/* ARM relocs. */
#define R_ARM_NONE 0 /* No reloc */
#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
+/* dlopen test for PIE objects.
+ 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/>. */
+
+/* This test attempts to open the (otherwise unrelated) PIE test
+ program elf/tst-pie1 and expects the attempt to fail. */
+
+#include <dlfcn.h>
+#include <stddef.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/support.h>
+
+static void
+test_mode (int mode)
+{
+ char *pie_path = xasprintf ("%s/elf/tst-pie1", support_objdir_root);
+ if (dlopen (pie_path, mode) != NULL)
+ FAIL_EXIT1 ("dlopen succeeded unexpectedly (%d)", mode);
+ const char *message = dlerror ();
+ const char *expected
+ = "cannot dynamically load position-independent executable";
+ if (strstr (message, expected) == NULL)
+ FAIL_EXIT1 ("unexpected error message (mode %d): %s", mode, message);
+}
+
+static int
+do_test (void)
+{
+ test_mode (RTLD_LAZY);
+ test_mode (RTLD_NOW);
+ return 0;
+}
+
+#include <support/test-driver.c>
--- /dev/null
+/* Basic tests for pldd program.
+ 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 <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <libgen.h>
+#include <stdbool.h>
+
+#include <array_length.h>
+#include <gnu/lib-names.h>
+
+#include <support/subprocess.h>
+#include <support/capture_subprocess.h>
+#include <support/check.h>
+
+static void
+target_process (void *arg)
+{
+ pause ();
+}
+
+/* The test runs in a container because pldd does not support tracing
+ a binary started by the loader iself (as with testrun.sh). */
+
+static int
+do_test (void)
+{
+ /* Create a copy of current test to check with pldd. */
+ struct support_subprocess target = support_subprocess (target_process, NULL);
+
+ /* Run 'pldd' on test subprocess. */
+ struct support_capture_subprocess pldd;
+ {
+ /* Three digits per byte plus null terminator. */
+ char pid[3 * sizeof (uint32_t) + 1];
+ snprintf (pid, array_length (pid), "%d", target.pid);
+
+ const char prog[] = "/usr/bin/pldd";
+
+ pldd = support_capture_subprogram (prog,
+ (char *const []) { (char *) prog, pid, NULL });
+
+ support_capture_subprocess_check (&pldd, "pldd", 0, sc_allow_stdout);
+ }
+
+ /* Check 'pldd' output. The test is expected to be linked against only
+ loader and libc. */
+ {
+ pid_t pid;
+ char buffer[512];
+#define STRINPUT(size) "%" # size "s"
+
+ FILE *out = fmemopen (pldd.out.buffer, pldd.out.length, "r");
+ TEST_VERIFY (out != NULL);
+
+ /* First line is in the form of <pid>: <full path of executable> */
+ TEST_COMPARE (fscanf (out, "%u: " STRINPUT (512), &pid, buffer), 2);
+
+ TEST_COMPARE (pid, target.pid);
+ TEST_COMPARE (strcmp (basename (buffer), "tst-pldd"), 0);
+
+ /* It expects only one loader and libc loaded by the program. */
+ bool interpreter_found = false, libc_found = false;
+ while (fgets (buffer, array_length (buffer), out) != NULL)
+ {
+ /* Ignore vDSO. */
+ if (buffer[0] != '/')
+ continue;
+
+ /* Remove newline so baseline (buffer) can compare against the
+ LD_SO and LIBC_SO macros unmodified. */
+ if (buffer[strlen(buffer)-1] == '\n')
+ buffer[strlen(buffer)-1] = '\0';
+
+ if (strcmp (basename (buffer), LD_SO) == 0)
+ {
+ TEST_COMPARE (interpreter_found, false);
+ interpreter_found = true;
+ continue;
+ }
+
+ if (strcmp (basename (buffer), LIBC_SO) == 0)
+ {
+ TEST_COMPARE (libc_found, false);
+ libc_found = true;
+ continue;
+ }
+ }
+ TEST_COMPARE (interpreter_found, true);
+ TEST_COMPARE (libc_found, true);
+
+ fclose (out);
+ }
+
+ support_capture_subprocess_free (&pldd);
+ support_process_terminate (&target);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
# endif
# define DT_1_SUPPORTED_MASK \
(DF_1_NOW | DF_1_NODELETE | DF_1_INITFIRST | DF_1_NOOPEN \
- | DF_1_ORIGIN | DF_1_NODEFLIB)
+ | DF_1_ORIGIN | DF_1_NODEFLIB | DF_1_PIE)
#endif /* !_ISOMAC */
#endif /* elf.h */
#ifdef USE_STAP_PROBE
+# include <stap-probe-machine.h>
# include <sys/sdt.h>
/* Our code uses one macro LIBC_PROBE (name, n, arg1, ..., argn).
tst-fts tst-fts-lfs tst-open-tmpfile \
tst-copy_file_range tst-getcwd-abspath \
-# This test includes the compat implementation of copy_file_range,
-# which uses internal, unexported libc functions.
-tests-static += tst-copy_file_range-compat
-tests-internal += tst-copy_file_range-compat
-
# Likewise for statx, but we do not need static linking here.
tests-internal += tst-statx
+++ /dev/null
-/* Emulation of copy_file_range.
- Copyright (C) 2017-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/>. */
-
-/* The following macros should be defined before including this
- file:
-
- COPY_FILE_RANGE_DECL Declaration specifiers for the function below.
- COPY_FILE_RANGE Name of the function to define. */
-
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <limits.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-COPY_FILE_RANGE_DECL
-ssize_t
-COPY_FILE_RANGE (int infd, __off64_t *pinoff,
- int outfd, __off64_t *poutoff,
- size_t length, unsigned int flags)
-{
- if (flags != 0)
- {
- __set_errno (EINVAL);
- return -1;
- }
-
- {
- struct stat64 instat;
- struct stat64 outstat;
- if (fstat64 (infd, &instat) != 0 || fstat64 (outfd, &outstat) != 0)
- return -1;
- if (S_ISDIR (instat.st_mode) || S_ISDIR (outstat.st_mode))
- {
- __set_errno (EISDIR);
- return -1;
- }
- if (!S_ISREG (instat.st_mode) || !S_ISREG (outstat.st_mode))
- {
- /* We need a regular input file so that the we can seek
- backwards in case of a write failure. */
- __set_errno (EINVAL);
- return -1;
- }
- if (instat.st_dev != outstat.st_dev)
- {
- /* Cross-device copies are not supported. */
- __set_errno (EXDEV);
- return -1;
- }
- }
-
- /* The output descriptor must not have O_APPEND set. */
- {
- int flags = __fcntl (outfd, F_GETFL);
- if (flags & O_APPEND)
- {
- __set_errno (EBADF);
- return -1;
- }
- }
-
- /* Avoid an overflow in the result. */
- if (length > SSIZE_MAX)
- length = SSIZE_MAX;
-
- /* Main copying loop. The buffer size is arbitrary and is a
- trade-off between stack size consumption, cache usage, and
- amortization of system call overhead. */
- size_t copied = 0;
- char buf[8192];
- while (length > 0)
- {
- size_t to_read = length;
- if (to_read > sizeof (buf))
- to_read = sizeof (buf);
-
- /* Fill the buffer. */
- ssize_t read_count;
- if (pinoff == NULL)
- read_count = read (infd, buf, to_read);
- else
- read_count = __libc_pread64 (infd, buf, to_read, *pinoff);
- if (read_count == 0)
- /* End of file reached prematurely. */
- return copied;
- if (read_count < 0)
- {
- if (copied > 0)
- /* Report the number of bytes copied so far. */
- return copied;
- return -1;
- }
- if (pinoff != NULL)
- *pinoff += read_count;
-
- /* Write the buffer part which was read to the destination. */
- char *end = buf + read_count;
- for (char *p = buf; p < end; )
- {
- ssize_t write_count;
- if (poutoff == NULL)
- write_count = write (outfd, p, end - p);
- else
- write_count = __libc_pwrite64 (outfd, p, end - p, *poutoff);
- if (write_count < 0)
- {
- /* Adjust the input read position to match what we have
- written, so that the caller can pick up after the
- error. */
- size_t written = p - buf;
- /* NB: This needs to be signed so that we can form the
- negative value below. */
- ssize_t overread = read_count - written;
- if (pinoff == NULL)
- {
- if (overread > 0)
- {
- /* We are on an error recovery path, so we
- cannot deal with failure here. */
- int save_errno = errno;
- (void) __libc_lseek64 (infd, -overread, SEEK_CUR);
- __set_errno (save_errno);
- }
- }
- else /* pinoff != NULL */
- *pinoff -= overread;
-
- if (copied + written > 0)
- /* Report the number of bytes copied so far. */
- return copied + written;
- return -1;
- }
- p += write_count;
- if (poutoff != NULL)
- *poutoff += write_count;
- } /* Write loop. */
-
- copied += read_count;
- length -= read_count;
- }
- return copied;
-}
-/* Generic implementation of copy_file_range.
+/* Stub implementation of copy_file_range.
Copyright (C) 2017-2019 Free Software Foundation, Inc.
This file is part of the GNU C Library.
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
-#define COPY_FILE_RANGE_DECL
-#define COPY_FILE_RANGE copy_file_range
+#include <errno.h>
+#include <unistd.h>
-#include <io/copy_file_range-compat.c>
+ssize_t
+copy_file_range (int infd, __off64_t *pinoff,
+ int outfd, __off64_t *poutoff,
+ size_t length, unsigned int flags)
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+stub_warning (copy_file_range)
+++ /dev/null
-/* Test the fallback implementation of copy_file_range.
- Copyright (C) 2017-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/>. */
-
-/* Get the declaration of the official copy_of_range function. */
-#include <unistd.h>
-
-/* Compile a local version of copy_file_range. */
-#define COPY_FILE_RANGE_DECL static
-#define COPY_FILE_RANGE copy_file_range_compat
-#include <io/copy_file_range-compat.c>
-
-/* Re-use the test, but run it against copy_file_range_compat defined
- above. */
-#define copy_file_range copy_file_range_compat
-#include "tst-copy_file_range.c"
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
-#include <libgen.h>
-#include <poll.h>
-#include <sched.h>
#include <stdbool.h>
#include <stdio.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/xunistd.h>
-#ifdef CLONE_NEWNS
-# include <sys/mount.h>
-#endif
/* Boolean flags which indicate whether to use pointers with explicit
output flags. */
static char *outfile;
static int outfd;
-/* Like the above, but on a different file system. xdevfile can be
- NULL if no suitable file system has been found. */
-static char *xdevfile;
-
/* Input and output offsets. Set according to do_inoff and do_outoff
before the test. The offsets themselves are always set to
zero. */
static off64_t outoff;
static off64_t *poutoff;
-/* These are a collection of copy sizes used in tests. The selection
- takes into account that the fallback implementation uses an
- internal buffer of 8192 bytes. */
+/* These are a collection of copy sizes used in tests. */
enum { maximum_size = 99999 };
static const int typical_sizes[] =
- { 0, 1, 2, 3, 1024, 2048, 4096, 8191, 8192, 8193, 16383, 16384, 16385,
- maximum_size };
+ { 0, 1, 2, 3, 1024, 2048, 4096, 8191, 8192, 8193, maximum_size };
/* The random contents of this array can be used as a pattern to check
for correct write operations. */
/* The size chosen by the test harness. */
static int current_size;
-/* Maximum writable file offset. Updated by find_maximum_offset
- below. */
-static off64_t maximum_offset;
-
-/* Error code when crossing the offset. */
-static int maximum_offset_errno;
-
-/* If true: Writes which cross the limit will fail. If false: Writes
- which cross the limit will result in a partial write. */
-static bool maximum_offset_hard_limit;
-
-/* Fills maximum_offset etc. above. Truncates outfd as a side
- effect. */
-static void
-find_maximum_offset (void)
-{
- xftruncate (outfd, 0);
- if (maximum_offset != 0)
- return;
-
- uint64_t upper = -1;
- upper >>= 1; /* Maximum of off64_t. */
- TEST_VERIFY ((off64_t) upper > 0);
- TEST_VERIFY ((off64_t) (upper + 1) < 0);
- if (lseek64 (outfd, upper, SEEK_SET) >= 0)
- {
- if (write (outfd, "", 1) == 1)
- FAIL_EXIT1 ("created a file larger than the off64_t range");
- }
-
- uint64_t lower = 1024 * 1024; /* A reasonable minimum file size. */
- /* Loop invariant: writing at lower succeeds, writing at upper fails. */
- while (lower + 1 < upper)
- {
- uint64_t middle = (lower + upper) / 2;
- if (test_verbose > 0)
- printf ("info: %s: remaining test range %" PRIu64 " .. %" PRIu64
- ", probe at %" PRIu64 "\n", __func__, lower, upper, middle);
- xftruncate (outfd, 0);
- if (lseek64 (outfd, middle, SEEK_SET) >= 0
- && write (outfd, "", 1) == 1)
- lower = middle;
- else
- upper = middle;
- }
- TEST_VERIFY (lower + 1 == upper);
- maximum_offset = lower;
- printf ("info: maximum writable file offset: %" PRIu64 " (%" PRIx64 ")\n",
- lower, lower);
-
- /* Check that writing at the valid offset actually works. */
- xftruncate (outfd, 0);
- xlseek (outfd, lower, SEEK_SET);
- TEST_COMPARE (write (outfd, "", 1), 1);
-
- /* Cross the boundary with a two-byte write. This can either result
- in a short write, or a failure. */
- xlseek (outfd, lower, SEEK_SET);
- ssize_t ret = write (outfd, " ", 2);
- if (ret < 0)
- {
- maximum_offset_errno = errno;
- maximum_offset_hard_limit = true;
- }
- else
- maximum_offset_hard_limit = false;
-
- /* Check that writing at the next offset actually fails. This also
- obtains the expected errno value. */
- xftruncate (outfd, 0);
- const char *action;
- if (lseek64 (outfd, lower + 1, SEEK_SET) != 0)
- {
- if (write (outfd, "", 1) != -1)
- FAIL_EXIT1 ("write to impossible offset %" PRIu64 " succeeded",
- lower + 1);
- action = "writing";
- int errno_copy = errno;
- if (maximum_offset_hard_limit)
- TEST_COMPARE (errno_copy, maximum_offset_errno);
- else
- maximum_offset_errno = errno_copy;
- }
- else
- {
- action = "seeking";
- maximum_offset_errno = errno;
- }
- printf ("info: %s out of range fails with %m (%d)\n",
- action, maximum_offset_errno);
-
- xftruncate (outfd, 0);
- xlseek (outfd, 0, SEEK_SET);
-}
-
/* Perform a copy of a file. */
static void
simple_file_copy (void)
free (bytes);
}
-/* Test that reading from a pipe willfails. */
-static void
-pipe_as_source (void)
-{
- int pipefds[2];
- xpipe (pipefds);
-
- for (int length = 0; length < 2; ++length)
- {
- if (test_verbose > 0)
- printf ("info: %s: length=%d\n", __func__, length);
-
- /* Make sure that there is something to copy in the pipe. */
- xwrite (pipefds[1], "@", 1);
-
- TEST_COMPARE (copy_file_range (pipefds[0], pinoff, outfd, poutoff,
- length, 0), -1);
- /* Linux 4.10 and later return EINVAL. Older kernels return
- EXDEV. */
- TEST_VERIFY (errno == EINVAL || errno == EXDEV);
- TEST_COMPARE (inoff, 0);
- TEST_COMPARE (outoff, 0);
- TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), 0);
-
- /* Make sure that nothing was read. */
- char buf = 'A';
- TEST_COMPARE (read (pipefds[0], &buf, 1), 1);
- TEST_COMPARE (buf, '@');
- }
-
- xclose (pipefds[0]);
- xclose (pipefds[1]);
-}
-
-/* Test that writing to a pipe fails. */
-static void
-pipe_as_destination (void)
-{
- /* Make sure that there is something to read in the input file. */
- xwrite (infd, "abc", 3);
- xlseek (infd, 0, SEEK_SET);
-
- int pipefds[2];
- xpipe (pipefds);
-
- for (int length = 0; length < 2; ++length)
- {
- if (test_verbose > 0)
- printf ("info: %s: length=%d\n", __func__, length);
-
- TEST_COMPARE (copy_file_range (infd, pinoff, pipefds[1], poutoff,
- length, 0), -1);
- /* Linux 4.10 and later return EINVAL. Older kernels return
- EXDEV. */
- TEST_VERIFY (errno == EINVAL || errno == EXDEV);
- TEST_COMPARE (inoff, 0);
- TEST_COMPARE (outoff, 0);
- TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 0);
-
- /* Make sure that nothing was written. */
- struct pollfd pollfd = { .fd = pipefds[0], .events = POLLIN, };
- TEST_COMPARE (poll (&pollfd, 1, 0), 0);
- }
-
- xclose (pipefds[0]);
- xclose (pipefds[1]);
-}
-
-/* Test a write failure after (potentially) writing some bytes.
- Failure occurs near the start of the buffer. */
-static void
-delayed_write_failure_beginning (void)
-{
- /* We need to write something to provoke the error. */
- if (current_size == 0)
- return;
- xwrite (infd, random_data, sizeof (random_data));
- xlseek (infd, 0, SEEK_SET);
-
- /* Write failure near the start. The actual error code varies among
- file systems. */
- find_maximum_offset ();
- off64_t where = maximum_offset;
-
- if (current_size == 1)
- ++where;
- outoff = where;
- if (do_outoff)
- xlseek (outfd, 1, SEEK_SET);
- else
- xlseek (outfd, where, SEEK_SET);
- if (maximum_offset_hard_limit || where > maximum_offset)
- {
- TEST_COMPARE (copy_file_range (infd, pinoff, outfd, poutoff,
- sizeof (random_data), 0), -1);
- TEST_COMPARE (errno, maximum_offset_errno);
- TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 0);
- TEST_COMPARE (inoff, 0);
- if (do_outoff)
- TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), 1);
- else
- TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), where);
- TEST_COMPARE (outoff, where);
- struct stat64 st;
- xfstat (outfd, &st);
- TEST_COMPARE (st.st_size, 0);
- }
- else
- {
- /* The offset is not a hard limit. This means we write one
- byte. */
- TEST_COMPARE (copy_file_range (infd, pinoff, outfd, poutoff,
- sizeof (random_data), 0), 1);
- if (do_inoff)
- {
- TEST_COMPARE (inoff, 1);
- TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 0);
- }
- else
- {
- TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 1);
- TEST_COMPARE (inoff, 0);
- }
- if (do_outoff)
- {
- TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), 1);
- TEST_COMPARE (outoff, where + 1);
- }
- else
- {
- TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), where + 1);
- TEST_COMPARE (outoff, where);
- }
- struct stat64 st;
- xfstat (outfd, &st);
- TEST_COMPARE (st.st_size, where + 1);
- }
-}
-
-/* Test a write failure after (potentially) writing some bytes.
- Failure occurs near the end of the buffer. */
-static void
-delayed_write_failure_end (void)
-{
- if (current_size <= 1)
- /* This would be same as the first test because there is not
- enough data to write to make a difference. */
- return;
- xwrite (infd, random_data, sizeof (random_data));
- xlseek (infd, 0, SEEK_SET);
-
- find_maximum_offset ();
- off64_t where = maximum_offset - current_size + 1;
- if (current_size == sizeof (random_data))
- /* Otherwise we do not reach the non-writable byte. */
- ++where;
- outoff = where;
- if (do_outoff)
- xlseek (outfd, 1, SEEK_SET);
- else
- xlseek (outfd, where, SEEK_SET);
- ssize_t ret = copy_file_range (infd, pinoff, outfd, poutoff,
- sizeof (random_data), 0);
- if (ret < 0)
- {
- TEST_COMPARE (ret, -1);
- TEST_COMPARE (errno, maximum_offset_errno);
- struct stat64 st;
- xfstat (outfd, &st);
- TEST_COMPARE (st.st_size, 0);
- }
- else
- {
- /* The first copy succeeded. This happens in the emulation
- because the internal buffer of limited size does not
- necessarily cross the off64_t boundary on the first write
- operation. */
- if (test_verbose > 0)
- printf ("info: copy_file_range (%zu) returned %zd\n",
- sizeof (random_data), ret);
- TEST_VERIFY (ret > 0);
- TEST_VERIFY (ret < maximum_size);
- struct stat64 st;
- xfstat (outfd, &st);
- TEST_COMPARE (st.st_size, where + ret);
- if (do_inoff)
- {
- TEST_COMPARE (inoff, ret);
- TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 0);
- }
- else
- TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), ret);
-
- char *buffer = xmalloc (ret);
- TEST_COMPARE (pread64 (outfd, buffer, ret, where), ret);
- TEST_VERIFY (memcmp (buffer, random_data, ret) == 0);
- free (buffer);
-
- /* The second copy fails. */
- TEST_COMPARE (copy_file_range (infd, pinoff, outfd, poutoff,
- sizeof (random_data), 0), -1);
- TEST_COMPARE (errno, maximum_offset_errno);
- }
-}
-
-/* Test a write failure across devices. */
-static void
-cross_device_failure (void)
-{
- if (xdevfile == NULL)
- /* Subtest not supported due to missing cross-device file. */
- return;
-
- /* We need something to write. */
- xwrite (infd, random_data, sizeof (random_data));
- xlseek (infd, 0, SEEK_SET);
-
- int xdevfd = xopen (xdevfile, O_RDWR | O_LARGEFILE, 0);
- TEST_COMPARE (copy_file_range (infd, pinoff, xdevfd, poutoff,
- current_size, 0), -1);
- TEST_COMPARE (errno, EXDEV);
- TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 0);
- struct stat64 st;
- xfstat (xdevfd, &st);
- TEST_COMPARE (st.st_size, 0);
-
- xclose (xdevfd);
-}
-
-/* Try to exercise ENOSPC behavior with a tempfs file system (so that
- we do not have to fill up a regular file system to get the error).
- This function runs in a subprocess, so that we do not change the
- mount namespace of the actual test process. */
-static void
-enospc_failure_1 (void *closure)
-{
-#ifdef CLONE_NEWNS
- support_become_root ();
-
- /* Make sure that we do not alter the file system mounts of the
- parents. */
- if (! support_enter_mount_namespace ())
- {
- printf ("warning: ENOSPC test skipped\n");
- return;
- }
-
- char *mountpoint = closure;
- if (mount ("none", mountpoint, "tmpfs", MS_NODEV | MS_NOEXEC,
- "size=500k") != 0)
- {
- printf ("warning: could not mount tmpfs at %s: %m\n", mountpoint);
- return;
- }
-
- /* The source file must reside on the same file system. */
- char *intmpfsfile = xasprintf ("%s/%s", mountpoint, "in");
- int intmpfsfd = xopen (intmpfsfile, O_RDWR | O_CREAT | O_LARGEFILE, 0600);
- xwrite (intmpfsfd, random_data, sizeof (random_data));
- xlseek (intmpfsfd, 1, SEEK_SET);
- inoff = 1;
-
- char *outtmpfsfile = xasprintf ("%s/%s", mountpoint, "out");
- int outtmpfsfd = xopen (outtmpfsfile, O_RDWR | O_CREAT | O_LARGEFILE, 0600);
-
- /* Fill the file with data until ENOSPC is reached. */
- while (true)
- {
- ssize_t ret = write (outtmpfsfd, random_data, sizeof (random_data));
- if (ret < 0 && errno != ENOSPC)
- FAIL_EXIT1 ("write to %s: %m", outtmpfsfile);
- if (ret < sizeof (random_data))
- break;
- }
- TEST_COMPARE (write (outtmpfsfd, "", 1), -1);
- TEST_COMPARE (errno, ENOSPC);
- off64_t maxsize = xlseek (outtmpfsfd, 0, SEEK_CUR);
- TEST_VERIFY_EXIT (maxsize > sizeof (random_data));
-
- /* Constructed the expected file contents. */
- char *expected = xmalloc (maxsize);
- TEST_COMPARE (pread64 (outtmpfsfd, expected, maxsize, 0), maxsize);
- /* Go back a little, so some bytes can be written. */
- enum { offset = 20000 };
- TEST_VERIFY_EXIT (offset < maxsize);
- TEST_VERIFY_EXIT (offset < sizeof (random_data));
- memcpy (expected + maxsize - offset, random_data + 1, offset);
-
- if (do_outoff)
- {
- outoff = maxsize - offset;
- xlseek (outtmpfsfd, 2, SEEK_SET);
- }
- else
- xlseek (outtmpfsfd, -offset, SEEK_CUR);
-
- /* First call is expected to succeed because we made room for some
- bytes. */
- TEST_COMPARE (copy_file_range (intmpfsfd, pinoff, outtmpfsfd, poutoff,
- maximum_size, 0), offset);
- if (do_inoff)
- {
- TEST_COMPARE (inoff, 1 + offset);
- TEST_COMPARE (xlseek (intmpfsfd, 0, SEEK_CUR), 1);
- }
- else
- TEST_COMPARE (xlseek (intmpfsfd, 0, SEEK_CUR), 1 + offset);
- if (do_outoff)
- {
- TEST_COMPARE (outoff, maxsize);
- TEST_COMPARE (xlseek (outtmpfsfd, 0, SEEK_CUR), 2);
- }
- else
- TEST_COMPARE (xlseek (outtmpfsfd, 0, SEEK_CUR), maxsize);
- struct stat64 st;
- xfstat (outtmpfsfd, &st);
- TEST_COMPARE (st.st_size, maxsize);
- char *actual = xmalloc (st.st_size);
- TEST_COMPARE (pread64 (outtmpfsfd, actual, st.st_size, 0), st.st_size);
- TEST_VERIFY (memcmp (expected, actual, maxsize) == 0);
-
- /* Second call should fail with ENOSPC. */
- TEST_COMPARE (copy_file_range (intmpfsfd, pinoff, outtmpfsfd, poutoff,
- maximum_size, 0), -1);
- TEST_COMPARE (errno, ENOSPC);
-
- /* Offsets should be unchanged. */
- if (do_inoff)
- {
- TEST_COMPARE (inoff, 1 + offset);
- TEST_COMPARE (xlseek (intmpfsfd, 0, SEEK_CUR), 1);
- }
- else
- TEST_COMPARE (xlseek (intmpfsfd, 0, SEEK_CUR), 1 + offset);
- if (do_outoff)
- {
- TEST_COMPARE (outoff, maxsize);
- TEST_COMPARE (xlseek (outtmpfsfd, 0, SEEK_CUR), 2);
- }
- else
- TEST_COMPARE (xlseek (outtmpfsfd, 0, SEEK_CUR), maxsize);
- TEST_COMPARE (xlseek (outtmpfsfd, 0, SEEK_END), maxsize);
- TEST_COMPARE (pread64 (outtmpfsfd, actual, maxsize, 0), maxsize);
- TEST_VERIFY (memcmp (expected, actual, maxsize) == 0);
-
- free (actual);
- free (expected);
-
- xclose (intmpfsfd);
- xclose (outtmpfsfd);
- free (intmpfsfile);
- free (outtmpfsfile);
-
-#else /* !CLONE_NEWNS */
- puts ("warning: ENOSPC test skipped (no mount namespaces)");
-#endif
-}
-
-/* Call enospc_failure_1 in a subprocess. */
-static void
-enospc_failure (void)
-{
- char *mountpoint
- = support_create_temp_directory ("tst-copy_file_range-enospc-");
- support_isolate_in_subprocess (enospc_failure_1, mountpoint);
- free (mountpoint);
-}
-
-/* The target file descriptor must have O_APPEND enabled. */
-static void
-oappend_failure (void)
-{
- /* Add data, to make sure we do not fail because there is
- insufficient input data. */
- xwrite (infd, random_data, current_size);
- xlseek (infd, 0, SEEK_SET);
-
- xclose (outfd);
- outfd = xopen (outfile, O_RDWR | O_APPEND, 0);
- TEST_COMPARE (copy_file_range (infd, pinoff, outfd, poutoff,
- current_size, 0), -1);
- TEST_COMPARE (errno, EBADF);
-}
-
/* Test that a short input file results in a shortened copy. */
static void
short_copy (void)
static struct test_case tests[] =
{
{ "simple_file_copy", simple_file_copy, .sizes = true },
- { "pipe_as_source", pipe_as_source, },
- { "pipe_as_destination", pipe_as_destination, },
- { "delayed_write_failure_beginning", delayed_write_failure_beginning,
- .sizes = true },
- { "delayed_write_failure_end", delayed_write_failure_end, .sizes = true },
- { "cross_device_failure", cross_device_failure, .sizes = true },
- { "enospc_failure", enospc_failure, },
- { "oappend_failure", oappend_failure, .sizes = true },
{ "short_copy", short_copy, .sizes = true },
};
*p = rand () >> 24;
infd = create_temp_file ("tst-copy_file_range-in-", &infile);
+ outfd = create_temp_file ("tst-copy_file_range-out-", &outfile);
{
- int outfd = create_temp_file ("tst-copy_file_range-out-", &outfile);
- if (!support_descriptor_supports_holes (outfd))
- FAIL_UNSUPPORTED ("File %s does not support holes", outfile);
- xclose (outfd);
- }
-
- /* Try to find a different directory from the default input/output
- file. */
- {
- struct stat64 instat;
- xfstat (infd, &instat);
- static const char *const candidates[] =
- { NULL, "/var/tmp", "/dev/shm" };
- for (const char *const *c = candidates; c < array_end (candidates); ++c)
- {
- const char *path = *c;
- char *to_free = NULL;
- if (path == NULL)
- {
- to_free = xreadlink ("/proc/self/exe");
- path = dirname (to_free);
- }
-
- struct stat64 cstat;
- xstat (path, &cstat);
- if (cstat.st_dev == instat.st_dev)
- {
- free (to_free);
- continue;
- }
-
- printf ("info: using alternate temporary files directory: %s\n", path);
- xdevfile = xasprintf ("%s/tst-copy_file_range-xdev-XXXXXX", path);
- free (to_free);
- break;
- }
- if (xdevfile != NULL)
+ ssize_t ret = copy_file_range (infd, NULL, outfd, NULL, 0, 0);
+ if (ret != 0)
{
- int xdevfd = mkstemp (xdevfile);
- if (xdevfd < 0)
- FAIL_EXIT1 ("mkstemp (\"%s\"): %m", xdevfile);
- struct stat64 xdevst;
- xfstat (xdevfd, &xdevst);
- TEST_VERIFY (xdevst.st_dev != instat.st_dev);
- add_temp_file (xdevfile);
- xclose (xdevfd);
+ if (errno == ENOSYS)
+ FAIL_UNSUPPORTED ("copy_file_range is not support on this system");
+ FAIL_EXIT1 ("copy_file_range probing call: %m");
}
- else
- puts ("warning: no alternate directory on different file system found");
}
xclose (infd);
+ xclose (outfd);
for (do_inoff = 0; do_inoff < 2; ++do_inoff)
for (do_outoff = 0; do_outoff < 2; ++do_outoff)
free (infile);
free (outfile);
- free (xdevfile);
return 0;
}
tst-setvbuf1 tst-popen1 tst-fgetwc bug-wsetpos tst-fseek \
tst-fwrite-error tst-ftell-partial-wide tst-ftell-active-handler \
tst-ftell-append tst-fputws tst-bz22415 tst-fgetc-after-eof \
- tst-sprintf-ub tst-sprintf-chk-ub
+ tst-sprintf-ub tst-sprintf-chk-ub tst-wfile-sync
tests-internal = tst-vtables tst-vtables-interposed tst-readline
# Add test-fopenloc only if shared library is enabled since it depends on
# shared localedata objects.
tests += tst-fopenloc
+# Add tst-bz24228 only if shared library is enabled since it can never meet its
+# objective with static linking because the relevant code just is not there.
+tests += tst-bz24228
endif
test-srcs = test-freopen
CFLAGS-tst-sprintf-ub.c += -Wno-restrict
CFLAGS-tst-sprintf-chk-ub.c += -Wno-restrict
+LDFLAGS-tst-bz24228 = -Wl,--version-script=tst-bz24228.map
+
tst_wprintf2-ARGS = "Some Text"
test-fmemopen-ENV = MALLOC_TRACE=$(objpfx)test-fmemopen.mtrace
tst-fopenloc-ENV = MALLOC_TRACE=$(objpfx)tst-fopenloc.mtrace
tst-bz22415-ENV = MALLOC_TRACE=$(objpfx)tst-bz22415.mtrace
+tst-bz24228-ENV = MALLOC_TRACE=$(objpfx)tst-bz24228.mtrace
generated += test-fmemopen.mtrace test-fmemopen.check
generated += tst-fopenloc.mtrace tst-fopenloc.check
aux := fileops genops stdfiles stdio strops
ifeq ($(build-shared),yes)
+generated += tst-bz24228.mtrace tst-bz24228.check
aux += oldfileops oldstdfiles
endif
ifeq (yes,$(build-shared))
# Run tst-fopenloc-cmp.out and tst-openloc-mem.out only if shared
# library is enabled since they depend on tst-fopenloc.out.
-tests-special += $(objpfx)tst-fopenloc-cmp.out $(objpfx)tst-fopenloc-mem.out
+tests-special += $(objpfx)tst-fopenloc-cmp.out $(objpfx)tst-fopenloc-mem.out \
+ $(objpfx)tst-bz24228-mem.out
endif
endif
$(objpfx)tst-ungetwc2.out: $(gen-locales)
$(objpfx)tst-widetext.out: $(gen-locales)
$(objpfx)tst_wprintf2.out: $(gen-locales)
+$(objpfx)tst-wfile-sync.out: $(gen-locales)
endif
$(objpfx)test-freopen.out: test-freopen.sh $(objpfx)test-freopen
$(objpfx)tst-bz22415-mem.out: $(objpfx)tst-bz22415.out
$(common-objpfx)malloc/mtrace $(objpfx)tst-bz22415.mtrace > $@; \
$(evaluate-test)
+
+$(objpfx)tst-bz24228-mem.out: $(objpfx)tst-bz24228.out
+ $(common-objpfx)malloc/mtrace $(objpfx)tst-bz24228.mtrace > $@; \
+ $(evaluate-test)
for (fp = (FILE *) _IO_list_all; fp; fp = fp->_chain)
{
+ int legacy = 0;
+
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)
+ if (__glibc_unlikely (_IO_vtable_offset (fp) != 0))
+ legacy = 1;
+#endif
+
if (! (fp->_flags & _IO_UNBUFFERED)
/* Iff stream is un-orientated, it wasn't used. */
- && fp->_mode != 0)
+ && (legacy || fp->_mode != 0))
{
#ifdef _IO_MTSAFE_IO
int cnt;
__sched_yield ();
#endif
- if (! dealloc_buffers && !(fp->_flags & _IO_USER_BUF))
+ if (! legacy && ! dealloc_buffers && !(fp->_flags & _IO_USER_BUF))
{
fp->_flags |= _IO_USER_BUF;
_IO_SETBUF (fp, NULL, 0);
- if (fp->_mode > 0)
+ if (! legacy && fp->_mode > 0)
_IO_wsetb (fp, NULL, NULL, 0);
#ifdef _IO_MTSAFE_IO
/* Make sure that never again the wide char functions can be
used. */
- fp->_mode = -1;
+ if (! legacy)
+ fp->_mode = -1;
}
#ifdef _IO_MTSAFE_IO
stdout->_vtable_offset = stderr->_vtable_offset =
((int) sizeof (struct _IO_FILE)
- (int) sizeof (struct _IO_FILE_complete));
+
+ if (_IO_stdin_.vtable != &_IO_old_file_jumps
+ || _IO_stdout_.vtable != &_IO_old_file_jumps
+ || _IO_stderr_.vtable != &_IO_old_file_jumps)
+ IO_set_accept_foreign_vtables (&_IO_vtable_check);
}
}
--- /dev/null
+/* BZ #24228 check for memory corruption in legacy libio
+ 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
+ <https://www.gnu.org/licenses/>. */
+
+#include <mcheck.h>
+#include <support/test-driver.h>
+
+static int
+do_test (void)
+{
+ mtrace ();
+ return 0;
+}
+
+#include <support/test-driver.c>
--- /dev/null
+# Hide the symbol from libc.so.6 to switch to the libio/oldfileops.c
+# implementation when it is available for the architecture.
+{
+ local: _IO_stdin_used;
+};
--- /dev/null
+/* Test that _IO_wfile_sync does not crash (bug 20568).
+ 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 <locale.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <support/check.h>
+#include <support/xunistd.h>
+
+static int
+do_test (void)
+{
+ TEST_VERIFY_EXIT (setlocale (LC_ALL, "de_DE.UTF-8") != NULL);
+ /* Fill the stdio buffer and advance the read pointer. */
+ TEST_VERIFY_EXIT (fgetwc (stdin) != WEOF);
+ /* This calls _IO_wfile_sync, it should not crash. */
+ TEST_VERIFY_EXIT (setvbuf (stdin, NULL, _IONBF, 0) == 0);
+ /* Verify that the external file offset has been synchronized. */
+ TEST_COMPARE (xlseek (0, 0, SEEK_CUR), 1);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
--- /dev/null
+This is a test of _IO_wfile_sync.
generate the wide characters up to the current reading
position. */
int nread;
-
+ size_t wnread = (fp->_wide_data->_IO_read_ptr
+ - fp->_wide_data->_IO_read_base);
fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
nread = (*cv->__codecvt_do_length) (cv, &fp->_wide_data->_IO_state,
fp->_IO_read_base,
- fp->_IO_read_end, delta);
+ fp->_IO_read_end, wnread);
fp->_IO_read_ptr = fp->_IO_read_base + nread;
delta = -(fp->_IO_read_end - fp->_IO_read_base - nread);
}
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>";/
"+:2:1913//01//01:1926//12//24:<U5927><U6B63>:%EC%Ey<U5E74>";/
- "+:2:1912//07//30:1912//12//31:<U5927><U6B63>:%EC<U5143><U5E74>";/
+ "+:1:1912//07//30:1912//12//31:<U5927><U6B63>:%EC<U5143><U5E74>";/
"+:6:1873//01//01:1912//07//29:<U660E><U6CBB>:%EC%Ey<U5E74>";/
"+:1:0001//01//01:1872//12//31:<U897F><U66A6>:%EC%Ey<U5E74>";/
"+:1:-0001//12//31:-*:<U7D00><U5143><U524D>:%EC%Ey<U5E74>"
tst-dynarray-at-fail \
ifneq (no,$(have-tunables))
-tests += tst-malloc-usable-tunables
+tests += tst-malloc-usable-tunables tst-mxfast
tests-static += tst-malloc-usable-static-tunables
endif
tst-malloc-usable-tunables-ENV = GLIBC_TUNABLES=glibc.malloc.check=3
tst-malloc-usable-static-tunables-ENV = $(tst-malloc-usable-tunables-ENV)
+tst-mxfast-ENV = GLIBC_TUNABLES=glibc.malloc.tcache_count=0:glibc.malloc.mxfast=0
+
ifeq ($(experimental-malloc),yes)
CPPFLAGS-malloc.c += -DUSE_TCACHE=1
else
TUNABLE_CALLBACK_FNDECL (set_tcache_count, size_t)
TUNABLE_CALLBACK_FNDECL (set_tcache_unsorted_limit, size_t)
#endif
+TUNABLE_CALLBACK_FNDECL (set_mxfast, size_t)
#else
/* Initialization routine. */
#include <string.h>
TUNABLE_GET (tcache_unsorted_limit, size_t,
TUNABLE_CALLBACK (set_tcache_unsorted_limit));
# endif
+ TUNABLE_GET (mxfast, size_t, TUNABLE_CALLBACK (set_mxfast));
#else
const char *s = NULL;
if (__glibc_likely (_environ != NULL))
/* This is another arbitrary limit, which tunables can change. Each
tcache bin will hold at most this number of chunks. */
# define TCACHE_FILL_COUNT 7
+
+/* Maximum chunks in tcache bins for tunables. This value must fit the range
+ of tcache->counts[] entries, else they may overflow. */
+# define MAX_TCACHE_COUNT UINT16_MAX
#endif
#define set_max_fast(s) \
global_max_fast = (((s) == 0) \
- ? SMALLBIN_WIDTH : ((s + SIZE_SZ) & ~MALLOC_ALIGN_MASK))
+ ? MIN_CHUNK_SIZE / 2 : ((s + SIZE_SZ) & ~MALLOC_ALIGN_MASK))
static inline INTERNAL_SIZE_T
get_max_fast (void)
time), this is for performance reasons. */
typedef struct tcache_perthread_struct
{
- char counts[TCACHE_MAX_BINS];
+ uint16_t counts[TCACHE_MAX_BINS];
tcache_entry *entries[TCACHE_MAX_BINS];
} tcache_perthread_struct;
tcache_put (mchunkptr chunk, size_t tc_idx)
{
tcache_entry *e = (tcache_entry *) chunk2mem (chunk);
- assert (tc_idx < TCACHE_MAX_BINS);
/* Mark this chunk as "in the tcache" so the test in _int_free will
detect a double free. */
tcache_get (size_t tc_idx)
{
tcache_entry *e = tcache->entries[tc_idx];
- assert (tc_idx < TCACHE_MAX_BINS);
- assert (tcache->entries[tc_idx] > 0);
tcache->entries[tc_idx] = e->next;
--(tcache->counts[tc_idx]);
e->key = NULL;
DIAG_PUSH_NEEDS_COMMENT;
if (tc_idx < mp_.tcache_bins
- /*&& tc_idx < TCACHE_MAX_BINS*/ /* to appease gcc */
&& tcache
- && tcache->entries[tc_idx] != NULL)
+ && tcache->counts[tc_idx] > 0)
{
return tcache_get (tc_idx);
}
{
victim->fd_nextsize = fwd;
victim->bk_nextsize = fwd->bk_nextsize;
+ if (__glibc_unlikely (fwd->bk_nextsize->fd_nextsize != fwd))
+ malloc_printerr ("malloc(): largebin double linked list corrupted (nextsize)");
fwd->bk_nextsize = victim;
victim->bk_nextsize->fd_nextsize = victim;
}
bck = fwd->bk;
+ if (bck->fd != fwd)
+ malloc_printerr ("malloc(): largebin double linked list corrupted (bk)");
}
}
else
__always_inline
do_set_tcache_count (size_t value)
{
- LIBC_PROBE (memory_tunable_tcache_count, 2, value, mp_.tcache_count);
- mp_.tcache_count = value;
+ if (value <= MAX_TCACHE_COUNT)
+ {
+ LIBC_PROBE (memory_tunable_tcache_count, 2, value, mp_.tcache_count);
+ mp_.tcache_count = value;
+ }
return 1;
}
}
#endif
+static inline int
+__always_inline
+do_set_mxfast (size_t value)
+{
+ if (value >= 0 && value <= MAX_FAST_SIZE)
+ {
+ LIBC_PROBE (memory_mallopt_mxfast, 2, value, get_max_fast ());
+ set_max_fast (value);
+ return 1;
+ }
+ return 0;
+}
+
int
__libc_mallopt (int param_number, int value)
{
switch (param_number)
{
case M_MXFAST:
- if (value >= 0 && value <= MAX_FAST_SIZE)
- {
- LIBC_PROBE (memory_mallopt_mxfast, 2, value, get_max_fast ());
- set_max_fast (value);
- }
- else
- res = 0;
+ do_set_mxfast (value);
break;
case M_TRIM_THRESHOLD:
__libc_lock_lock (ar_ptr->mutex);
+ /* Account for top chunk. The top-most available chunk is
+ treated specially and is never in any bin. See "initial_top"
+ comments. */
+ avail = chunksize (ar_ptr->top);
+ nblocks = 1; /* Top always exists. */
+
for (size_t i = 0; i < NFASTBINS; ++i)
{
mchunkptr p = fastbin (ar_ptr, i);
for (size_t i = 0; i < nsizes; ++i)
if (sizes[i].count != 0 && i != NFASTBINS)
- fprintf (fp, " \
+ fprintf (fp, "\
<size from=\"%zu\" to=\"%zu\" total=\"%zu\" count=\"%zu\"/>\n",
sizes[i].from, sizes[i].to, sizes[i].total, sizes[i].count);
return res;
}
+static void tr_freehook (void *, const void *);
+static void * tr_mallochook (size_t, const void *);
+static void * tr_reallochook (void *, size_t, const void *);
+static void * tr_memalignhook (size_t, size_t, const void *);
+
+/* Set all the default non-trace hooks. */
+static __always_inline void
+set_default_hooks (void)
+{
+ __free_hook = tr_old_free_hook;
+ __malloc_hook = tr_old_malloc_hook;
+ __realloc_hook = tr_old_realloc_hook;
+ __memalign_hook = tr_old_memalign_hook;
+}
+
+/* Set all of the tracing hooks used for mtrace. */
+static __always_inline void
+set_trace_hooks (void)
+{
+ __free_hook = tr_freehook;
+ __malloc_hook = tr_mallochook;
+ __realloc_hook = tr_reallochook;
+ __memalign_hook = tr_memalignhook;
+}
+
+/* Save the current set of hooks as the default hooks. */
+static __always_inline void
+save_default_hooks (void)
+{
+ tr_old_free_hook = __free_hook;
+ tr_old_malloc_hook = __malloc_hook;
+ tr_old_realloc_hook = __realloc_hook;
+ tr_old_memalign_hook = __memalign_hook;
+}
+
static void
tr_freehook (void *ptr, const void *caller)
{
tr_break ();
__libc_lock_lock (lock);
}
- __free_hook = tr_old_free_hook;
+ set_default_hooks ();
if (tr_old_free_hook != NULL)
(*tr_old_free_hook)(ptr, caller);
else
free (ptr);
- __free_hook = tr_freehook;
+ set_trace_hooks ();
__libc_lock_unlock (lock);
}
Dl_info mem;
Dl_info *info = lock_and_info (caller, &mem);
- __malloc_hook = tr_old_malloc_hook;
+ set_default_hooks ();
if (tr_old_malloc_hook != NULL)
hdr = (void *) (*tr_old_malloc_hook)(size, caller);
else
hdr = (void *) malloc (size);
- __malloc_hook = tr_mallochook;
+ set_trace_hooks ();
tr_where (caller, info);
/* We could be printing a NULL here; that's OK. */
Dl_info mem;
Dl_info *info = lock_and_info (caller, &mem);
- __free_hook = tr_old_free_hook;
- __malloc_hook = tr_old_malloc_hook;
- __realloc_hook = tr_old_realloc_hook;
+ set_default_hooks ();
if (tr_old_realloc_hook != NULL)
hdr = (void *) (*tr_old_realloc_hook)(ptr, size, caller);
else
hdr = (void *) realloc (ptr, size);
- __free_hook = tr_freehook;
- __malloc_hook = tr_mallochook;
- __realloc_hook = tr_reallochook;
+ set_trace_hooks ();
tr_where (caller, info);
if (hdr == NULL)
Dl_info mem;
Dl_info *info = lock_and_info (caller, &mem);
- __memalign_hook = tr_old_memalign_hook;
- __malloc_hook = tr_old_malloc_hook;
+ set_default_hooks ();
if (tr_old_memalign_hook != NULL)
hdr = (void *) (*tr_old_memalign_hook)(alignment, size, caller);
else
hdr = (void *) memalign (alignment, size);
- __memalign_hook = tr_memalignhook;
- __malloc_hook = tr_mallochook;
+ set_trace_hooks ();
tr_where (caller, info);
/* We could be printing a NULL here; that's OK. */
malloc_trace_buffer = mtb;
setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE);
fprintf (mallstream, "= Start\n");
- tr_old_free_hook = __free_hook;
- __free_hook = tr_freehook;
- tr_old_malloc_hook = __malloc_hook;
- __malloc_hook = tr_mallochook;
- tr_old_realloc_hook = __realloc_hook;
- __realloc_hook = tr_reallochook;
- tr_old_memalign_hook = __memalign_hook;
- __memalign_hook = tr_memalignhook;
+ save_default_hooks ();
+ set_trace_hooks ();
#ifdef _LIBC
if (!added_atexit_handler)
{
file. */
FILE *f = mallstream;
mallstream = NULL;
- __free_hook = tr_old_free_hook;
- __malloc_hook = tr_old_malloc_hook;
- __realloc_hook = tr_old_realloc_hook;
- __memalign_hook = tr_old_memalign_hook;
+ set_default_hooks ();
fprintf (f, "= End\n");
fclose (f);
void * ptr_to_realloc;
test_setup ();
+ DIAG_PUSH_NEEDS_COMMENT;
+#if __GNUC_PREREQ (7, 0)
+ /* GCC 7 warns about too-large allocations; here we want to test
+ that they fail. */
+ DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than=");
+#endif
TEST_VERIFY (malloc (size) == NULL);
+#if __GNUC_PREREQ (7, 0)
+ DIAG_POP_NEEDS_COMMENT;
+#endif
TEST_VERIFY (errno == ENOMEM);
ptr_to_realloc = malloc (16);
TEST_VERIFY_EXIT (ptr_to_realloc != NULL);
test_setup ();
+#if __GNUC_PREREQ (7, 0)
+ DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than=");
+#endif
TEST_VERIFY (realloc (ptr_to_realloc, size) == NULL);
+#if __GNUC_PREREQ (7, 0)
+ DIAG_POP_NEEDS_COMMENT;
+#endif
TEST_VERIFY (errno == ENOMEM);
free (ptr_to_realloc);
for (align = 1; align <= pagesize; align *= 2)
{
test_setup ();
+#if __GNUC_PREREQ (7, 0)
+ DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than=");
+#endif
TEST_VERIFY (memalign (align, size) == NULL);
+#if __GNUC_PREREQ (7, 0)
+ DIAG_POP_NEEDS_COMMENT;
+#endif
TEST_VERIFY (errno == ENOMEM);
/* posix_memalign expects an alignment that is a power of 2 *and* a
if ((size % align) == 0)
{
test_setup ();
+#if __GNUC_PREREQ (7, 0)
+ DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than=");
+#endif
TEST_VERIFY (aligned_alloc (align, size) == NULL);
+#if __GNUC_PREREQ (7, 0)
+ DIAG_POP_NEEDS_COMMENT;
+#endif
TEST_VERIFY (errno == ENOMEM);
}
}
/* Both valloc and pvalloc return page-aligned memory. */
test_setup ();
+#if __GNUC_PREREQ (7, 0)
+ DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than=");
+#endif
TEST_VERIFY (valloc (size) == NULL);
+#if __GNUC_PREREQ (7, 0)
+ DIAG_POP_NEEDS_COMMENT;
+#endif
TEST_VERIFY (errno == ENOMEM);
test_setup ();
+#if __GNUC_PREREQ (7, 0)
+ DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than=");
+#endif
TEST_VERIFY (pvalloc (size) == NULL);
+#if __GNUC_PREREQ (7, 0)
+ DIAG_POP_NEEDS_COMMENT;
+#endif
TEST_VERIFY (errno == ENOMEM);
}
#include <stdio.h>
#include <string.h>
#include <unistd.h>
+#include <libc-diag.h>
static int errors = 0;
errno = 0;
+ DIAG_PUSH_NEEDS_COMMENT;
+#if __GNUC_PREREQ (7, 0)
+ /* GCC 7 warns about too-large allocations; here we want to test
+ that they fail. */
+ DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than=");
+#endif
/* An attempt to allocate a huge value should return NULL and set
errno to ENOMEM. */
p = memalign (sizeof (void *), -1);
+#if __GNUC_PREREQ (7, 0)
+ DIAG_POP_NEEDS_COMMENT;
+#endif
save = errno;
--- /dev/null
+/* Test that glibc.malloc.mxfast tunable works.
+ 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/>. */
+
+/* This test verifies that setting the glibc.malloc.mxfast tunable to
+ zero results in free'd blocks being returned to the small bins, not
+ the fast bins. */
+
+#include <malloc.h>
+#include <support/check.h>
+
+int
+do_test (void)
+{
+ struct mallinfo m;
+ char *volatile p1;
+ char *volatile p2;
+
+ /* Arbitrary value; must be in default fastbin range. */
+ p1 = malloc (3);
+ /* Something large so that p1 isn't a "top block" */
+ p2 = malloc (512);
+ free (p1);
+
+ m = mallinfo ();
+
+ /* This will fail if there are any blocks in the fastbins. */
+ TEST_COMPARE (m.smblks, 0);
+
+ /* To keep gcc happy. */
+ free (p2);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
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-rwlock-pwn
+ tst-rwlock-pwn \
+ tst-rwlock-tryrdlock-stall tst-rwlock-trywrlock-stall
tests-internal := tst-rwlock19 tst-rwlock20 \
tst-sem11 tst-sem12 tst-sem13 \
/* Place the thread descriptor at the end of the stack. */
#if TLS_TCB_AT_TP
- pd = (struct pthread *) ((char *) mem + size) - 1;
+ pd = (struct pthread *) ((((uintptr_t) mem + size)
+ - TLS_TCB_SIZE)
+ & ~__static_tls_align_m1);
#elif TLS_DTV_AT_TP
pd = (struct pthread *) ((((uintptr_t) mem + size
- __static_tls_size)
pthread_cleanup_pop (0);
}
+ void *pd_result = pd->result;
if (__glibc_likely (result == 0))
{
/* We mark the thread as terminated and as joined. */
/* Store the return value if the caller is interested. */
if (thread_return != NULL)
- *thread_return = pd->result;
+ *thread_return = pd_result;
/* Free the TCB. */
__free_tcb (pd);
else
pd->joinid = NULL;
- LIBC_PROBE (pthread_join_ret, 3, threadid, result, pd->result);
+ LIBC_PROBE (pthread_join_ret, 3, threadid, result, pd_result);
return result;
}
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;
}
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);
}
/* 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
+/* 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>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
-
+#include <stdint.h>
+#include <inttypes.h>
+#include <support/support.h>
+#include <support/check.h>
+#include <support/xthread.h>
struct test_s
{
- int a;
- int b;
+ __attribute__ ((aligned(0x20))) int a;
+ __attribute__ ((aligned(0x200))) int b;
};
#define INIT_A 1
.b = INIT_B
};
+/* Use noinline in combination with not static to ensure that the
+ alignment check is really done. Otherwise it was optimized out! */
+__attribute__ ((noinline)) void
+check_alignment (const char *thr_name, const char *ptr_name,
+ int *ptr, int alignment)
+{
+ uintptr_t offset_aligment = ((uintptr_t) ptr) & (alignment - 1);
+ if (offset_aligment)
+ {
+ FAIL_EXIT1 ("%s (%p) is not 0x%x-byte aligned in %s thread\n",
+ ptr_name, ptr, alignment, thr_name);
+ }
+}
+
+static void
+check_s (const char *thr_name)
+{
+ if (s.a != INIT_A || s.b != INIT_B)
+ FAIL_EXIT1 ("initial value of s in %s thread wrong\n", thr_name);
+
+ check_alignment (thr_name, "s.a", &s.a, 0x20);
+ check_alignment (thr_name, "s.b", &s.b, 0x200);
+}
static void *
tf (void *arg)
{
- if (s.a != INIT_A || s.b != INIT_B)
- {
- puts ("initial value of s in child thread wrong");
- exit (1);
- }
+ check_s ("child");
++s.a;
int
do_test (void)
{
- if (s.a != INIT_A || s.b != INIT_B)
- {
- puts ("initial value of s in main thread wrong");
- exit (1);
- }
+ check_s ("main");
pthread_attr_t a;
- if (pthread_attr_init (&a) != 0)
- {
- puts ("attr_init failed");
- exit (1);
- }
+ xpthread_attr_init (&a);
- if (pthread_attr_setstacksize (&a, 1 * 1024 * 1024) != 0)
- {
- puts ("attr_setstacksize failed");
- return 1;
- }
+#define STACK_SIZE (1 * 1024 * 1024)
+ xpthread_attr_setstacksize (&a, STACK_SIZE);
#define N 10
int i;
pthread_t th[M];
int j;
for (j = 0; j < M; ++j, ++s.a)
- if (pthread_create (&th[j], &a, tf, NULL) != 0)
- {
- puts ("pthread_create failed");
- exit (1);
- }
+ th[j] = xpthread_create (&a, tf, NULL);
for (j = 0; j < M; ++j)
- if (pthread_join (th[j], NULL) != 0)
- {
- puts ("pthread_join failed");
- exit (1);
- }
+ xpthread_join (th[j]);
}
- if (pthread_attr_destroy (&a) != 0)
- {
- puts ("attr_destroy failed");
- exit (1);
- }
+ /* Also check the alignment of the tls variables if a misaligned stack is
+ specified. */
+ pthread_t th;
+ void *thr_stack = NULL;
+ thr_stack = xposix_memalign (0x200, STACK_SIZE + 1);
+ xpthread_attr_setstack (&a, thr_stack + 1, STACK_SIZE);
+ th = xpthread_create (&a, tf, NULL);
+ xpthread_join (th);
+ free (thr_stack);
+
+ xpthread_attr_destroy (&a);
return 0;
}
-
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
xtests = bug-erange
tests-container = \
- tst-nss-test3
+ tst-nss-test3 \
+ tst-nss-db-endpwent \
+ tst-nss-db-endgrent
# Tests which need libdl
ifeq (yes,$(build-shared))
void
internal_endent (struct nss_db_map *mapping)
{
- munmap (mapping->header, mapping->len);
+ if (mapping->header != NULL)
+ {
+ munmap (mapping->header, mapping->len);
+ mapping->header = NULL;
+ }
}
--- /dev/null
+/* Test for endgrent changing errno for BZ #24696
+ 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 <stdlib.h>
+#include <sys/types.h>
+#include <grp.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <support/check.h>
+#include <support/support.h>
+
+/* The following test verifies that if the db NSS Service is initialized
+ with no database (getgrent), that a subsequent closure (endgrent) does
+ not set errno. In the case of the db service it is not an error to close
+ the service and so it should not set errno. */
+
+static int
+do_test (void)
+{
+ /* Just make sure it's not there, although usually it won't be. */
+ unlink ("/var/db/group.db");
+
+ /* This, in conjunction with the testroot's nsswitch.conf, causes
+ the nss_db module to be "connected" and initialized - but the
+ testroot has no group.db, so no mapping will be created. */
+ getgrent ();
+
+ errno = 0;
+
+ /* Before the fix, this would call munmap (NULL) and set errno. */
+ endgrent ();
+
+ if (errno != 0)
+ FAIL_EXIT1 ("endgrent set errno to %d\n", errno);
+
+ return 0;
+}
+#include <support/test-driver.c>
--- /dev/null
+group : db files
--- /dev/null
+/* Test for endpwent->getpwent crash for BZ #24695
+ 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 <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <pwd.h>
+
+#include <support/support.h>
+#include <support/check.h>
+
+/* It is entirely allowed to start with a getpwent call without
+ resetting the state of the service via a call to setpwent.
+ You can also call getpwent more times than you have entries in
+ the service, and it should not fail. This test iteratates the
+ database once, gets to the end, and then attempts a second
+ iteration to look for crashes. */
+
+static void
+try_it (void)
+{
+ struct passwd *pw;
+
+ /* setpwent is intentionally omitted here. The first call to
+ getpwent detects that it's first and initializes. The second
+ time try_it is called, this "first call" was not detected before
+ the fix, and getpwent would crash. */
+
+ while ((pw = getpwent ()) != NULL)
+ ;
+
+ /* We only care if this segfaults or not. */
+ endpwent ();
+}
+
+static int
+do_test (void)
+{
+ char *cmd;
+
+ cmd = xasprintf ("%s/makedb -o /var/db/passwd.db /var/db/passwd.in",
+ support_bindir_prefix);
+ system (cmd);
+ free (cmd);
+
+ try_it ();
+ try_it ();
+
+ return 0;
+}
+#include <support/test-driver.c>
--- /dev/null
+passwd: db
--- /dev/null
+.root root:x:0:0:root:/root:/bin/bash
+=0 root:x:0:0:root:/root:/bin/bash
+.bin bin:x:1:1:bin:/bin:/sbin/nologin
+=1 bin:x:1:1:bin:/bin:/sbin/nologin
32 -- "natural" 32-bit type (always int)
64 -- "natural" 64-bit type (long or long long)
LONG32 -- 32-bit type, traditionally long
- QUAD -- 64-bit type, always long long
+ QUAD -- 64-bit type, traditionally long long
WORD -- natural type of __WORDSIZE bits (int or long)
LONGWORD -- type of __WORDSIZE bits, traditionally long
#define __SLONGWORD_TYPE long int
#define __ULONGWORD_TYPE unsigned long int
#if __WORDSIZE == 32
-# define __SQUAD_TYPE __quad_t
-# define __UQUAD_TYPE __u_quad_t
+# define __SQUAD_TYPE __int64_t
+# define __UQUAD_TYPE __uint64_t
# define __SWORD_TYPE int
# define __UWORD_TYPE unsigned int
# define __SLONG32_TYPE long int
# define __ULONG32_TYPE unsigned long int
-# define __S64_TYPE __quad_t
-# define __U64_TYPE __u_quad_t
+# define __S64_TYPE __int64_t
+# define __U64_TYPE __uint64_t
/* We want __extension__ before typedef's that use nonstandard base types
such as `long long' in C89 mode. */
# define __STD_TYPE __extension__ typedef
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;
}
}
#include <bits/stdint-intn.h>
-#if !__GNUC_PREREQ (2, 7)
-
/* These were defined by ISO C without the first `_'. */
-typedef unsigned char u_int8_t;
-typedef unsigned short int u_int16_t;
-typedef unsigned int u_int32_t;
-# if __WORDSIZE == 64
-typedef unsigned long int u_int64_t;
-# else
-__extension__ typedef unsigned long long int u_int64_t;
-# endif
-
-typedef int register_t;
-
-#else
-
-/* For GCC 2.7 and later, we can use specific type-size attributes. */
-# define __u_intN_t(N, MODE) \
- typedef unsigned int u_int##N##_t __attribute__ ((__mode__ (MODE)))
-
-__u_intN_t (8, __QI__);
-__u_intN_t (16, __HI__);
-__u_intN_t (32, __SI__);
-__u_intN_t (64, __DI__);
+typedef __uint8_t u_int8_t;
+typedef __uint16_t u_int16_t;
+typedef __uint32_t u_int32_t;
+typedef __uint64_t u_int64_t;
+#if __GNUC_PREREQ (2, 7)
typedef int register_t __attribute__ ((__mode__ (__word__)));
-
+#else
+typedef int register_t;
+#endif
/* Some code from BIND tests this macro to see if the types above are
defined. */
-#endif
#define __BIT_TYPES_DEFINED__ 1
-/* BZ #18877 and #21270 mmap offset test.
+/* BZ #18877, BZ #21270, and BZ #24699 mmap offset test.
Copyright (C) 2015-2019 Free Software Foundation, Inc.
This file is part of the GNU C Library.
#include <unistd.h>
#include <errno.h>
#include <sys/mman.h>
+#include <mmap_info.h>
#include <support/check.h>
/* Check if invalid offset are handled correctly by mmap. */
static int
-do_test_bz21270 (void)
+do_test_large_offset (void)
{
/* For architectures with sizeof (off_t) < sizeof (off64_t) mmap is
implemented with __SYS_mmap2 syscall and the offset is represented in
const size_t length = 4096;
void *addr = mmap64 (NULL, length, prot, flags, fd, offset);
- if (sizeof (off_t) < sizeof (off64_t))
+ if (mmap64_maximum_offset (page_shift) < UINT64_MAX)
{
if ((addr != MAP_FAILED) && (errno != EINVAL))
FAIL_RET ("mmap succeed");
int ret = 0;
ret += do_test_bz18877 ();
- ret += do_test_bz21270 ();
+ ret += do_test_large_offset ();
return ret;
}
# License along with the GNU C Library; if not, see
# <http://www.gnu.org/licenses/>.
-# Check installed headers for cleanliness. For each header, confirm
-# that it's possible to compile a file that includes that header and
-# does nothing else, in several different compilation modes. Also,
-# scan the header for a set of obsolete typedefs that should no longer
-# appear.
+# For each installed header, confirm that it's possible to compile a
+# file that includes that header and does nothing else, in several
+# different compilation modes.
# These compilation switches assume GCC or compatible, which is probably
# fine since we also assume that when _building_ glibc.
# These are probably the most commonly used three.
lib_modes="-D_DEFAULT_SOURCE=1 -D_GNU_SOURCE=1 -D_XOPEN_SOURCE=700"
-# sys/types.h+bits/types.h have to define the obsolete types.
-# rpc(svc)/* have the obsolete types too deeply embedded in their API
-# to remove.
-skip_obsolete_type_check='*/sys/types.h|*/bits/types.h|*/rpc/*|*/rpcsvc/*'
-obsolete_type_re=\
-'\<((__)?(quad_t|u(short|int|long|_(char|short|int([0-9]+_t)?|long|quad_t))))\>'
-
if [ $# -lt 3 ]; then
echo "usage: $0 c|c++ \"compile command\" header header header..." >&2
exit 2
(c)
lang_modes="$c_modes"
cih_test_c=$(mktemp ${TMPDIR-/tmp}/cih_test_XXXXXX.c)
- already="$skip_obsolete_type_check"
;;
(c++)
lang_modes="$cxx_modes"
cih_test_c=$(mktemp ${TMPDIR-/tmp}/cih_test_XXXXXX.cc)
- # The obsolete-type check can be skipped for C++; it is
- # sufficient to do it for C.
- already="*"
;;
(*)
echo "usage: $0 c|c++ \"compile command\" header header header..." >&2
int avoid_empty_translation_unit;
EOF
if $cc_cmd -fsyntax-only $lang_mode "$cih_test_c" 2>&1
- then
- includes=$($cc_cmd -fsyntax-only -H $lang_mode \
- "$cih_test_c" 2>&1 | sed -ne 's/^[.][.]* //p')
- for h in $includes; do
- # Don't repeat work.
- eval 'case "$h" in ('"$already"') continue;; esac'
-
- if grep -qE "$obsolete_type_re" "$h"; then
- echo "*** Obsolete types detected:"
- grep -HE "$obsolete_type_re" "$h"
- failed=1
- fi
- already="$already|$h"
- done
- else
- failed=1
+ then :
+ else failed=1
fi
done
done
--- /dev/null
+#! /usr/bin/python3
+# 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/>.
+
+"""Verifies that installed headers do not use any obsolete constructs:
+ * legacy BSD typedefs superseded by <stdint.h>:
+ ushort uint ulong u_char u_short u_int u_long u_intNN_t quad_t u_quad_t
+ (sys/types.h is allowed to _define_ these types, but not to use them
+ to define anything else).
+"""
+
+import argparse
+import collections
+import re
+import sys
+
+# Simplified lexical analyzer for C preprocessing tokens.
+# Does not implement trigraphs.
+# Does not implement backslash-newline in the middle of any lexical
+# item other than a string literal.
+# Does not implement universal-character-names in identifiers.
+# Treats prefixed strings (e.g. L"...") as two tokens (L and "...")
+# Accepts non-ASCII characters only within comments and strings.
+
+# Caution: The order of the outermost alternation matters.
+# STRING must be before BAD_STRING, CHARCONST before BAD_CHARCONST,
+# BLOCK_COMMENT before BAD_BLOCK_COM before PUNCTUATOR, and OTHER must
+# be last.
+# Caution: There should be no capturing groups other than the named
+# captures in the outermost alternation.
+
+# For reference, these are all of the C punctuators as of C11:
+# [ ] ( ) { } , ; ? ~
+# ! != * *= / /= ^ ^= = ==
+# # ##
+# % %= %> %: %:%:
+# & &= &&
+# | |= ||
+# + += ++
+# - -= -- ->
+# . ...
+# : :>
+# < <% <: << <<= <=
+# > >= >> >>=
+
+# The BAD_* tokens are not part of the official definition of pp-tokens;
+# they match unclosed strings, character constants, and block comments,
+# so that the regex engine doesn't have to backtrack all the way to the
+# beginning of a broken construct and then emit dozens of junk tokens.
+
+PP_TOKEN_RE_ = re.compile(r"""
+ (?P<STRING> \"(?:[^\"\\\r\n]|\\(?:[\r\n -~]|\r\n))*\")
+ |(?P<BAD_STRING> \"(?:[^\"\\\r\n]|\\[ -~])*)
+ |(?P<CHARCONST> \'(?:[^\'\\\r\n]|\\(?:[\r\n -~]|\r\n))*\')
+ |(?P<BAD_CHARCONST> \'(?:[^\'\\\r\n]|\\[ -~])*)
+ |(?P<BLOCK_COMMENT> /\*(?:\*(?!/)|[^*])*\*/)
+ |(?P<BAD_BLOCK_COM> /\*(?:\*(?!/)|[^*])*\*?)
+ |(?P<LINE_COMMENT> //[^\r\n]*)
+ |(?P<IDENT> [_a-zA-Z][_a-zA-Z0-9]*)
+ |(?P<PP_NUMBER> \.?[0-9](?:[0-9a-df-oq-zA-DF-OQ-Z_.]|[eEpP][+-]?)*)
+ |(?P<PUNCTUATOR>
+ [,;?~(){}\[\]]
+ | [!*/^=]=?
+ | \#\#?
+ | %(?:[=>]|:(?:%:)?)?
+ | &[=&]?
+ |\|[=|]?
+ |\+[=+]?
+ | -[=->]?
+ |\.(?:\.\.)?
+ | :>?
+ | <(?:[%:]|<(?:=|<=?)?)?
+ | >(?:=|>=?)?)
+ |(?P<ESCNL> \\(?:\r|\n|\r\n))
+ |(?P<WHITESPACE> [ \t\n\r\v\f]+)
+ |(?P<OTHER> .)
+""", re.DOTALL | re.VERBOSE)
+
+HEADER_NAME_RE_ = re.compile(r"""
+ < [^>\r\n]+ >
+ | " [^"\r\n]+ "
+""", re.DOTALL | re.VERBOSE)
+
+ENDLINE_RE_ = re.compile(r"""\r|\n|\r\n""")
+
+# based on the sample code in the Python re documentation
+Token_ = collections.namedtuple("Token", (
+ "kind", "text", "line", "column", "context"))
+Token_.__doc__ = """
+ One C preprocessing token, comment, or chunk of whitespace.
+ 'kind' identifies the token type, which will be one of:
+ STRING, CHARCONST, BLOCK_COMMENT, LINE_COMMENT, IDENT,
+ PP_NUMBER, PUNCTUATOR, ESCNL, WHITESPACE, HEADER_NAME,
+ or OTHER. The BAD_* alternatives in PP_TOKEN_RE_ are
+ handled within tokenize_c, below.
+
+ 'text' is the sequence of source characters making up the token;
+ no decoding whatsoever is performed.
+
+ 'line' and 'column' give the position of the first character of the
+ token within the source file. They are both 1-based.
+
+ 'context' indicates whether or not this token occurred within a
+ preprocessing directive; it will be None for running text,
+ '<null>' for the leading '#' of a directive line (because '#'
+ all by itself on a line is a "null directive"), or the name of
+ the directive for tokens within a directive line, starting with
+ the IDENT for the name itself.
+"""
+
+def tokenize_c(file_contents, reporter):
+ """Yield a series of Token objects, one for each preprocessing
+ token, comment, or chunk of whitespace within FILE_CONTENTS.
+ The REPORTER object is expected to have one method,
+ reporter.error(token, message), which will be called to
+ indicate a lexical error at the position of TOKEN.
+ If MESSAGE contains the four-character sequence '{!r}', that
+ is expected to be replaced by repr(token.text).
+ """
+
+ Token = Token_
+ PP_TOKEN_RE = PP_TOKEN_RE_
+ ENDLINE_RE = ENDLINE_RE_
+ HEADER_NAME_RE = HEADER_NAME_RE_
+
+ line_num = 1
+ line_start = 0
+ pos = 0
+ limit = len(file_contents)
+ directive = None
+ at_bol = True
+ while pos < limit:
+ if directive == "include":
+ mo = HEADER_NAME_RE.match(file_contents, pos)
+ if mo:
+ kind = "HEADER_NAME"
+ directive = "after_include"
+ else:
+ mo = PP_TOKEN_RE.match(file_contents, pos)
+ kind = mo.lastgroup
+ if kind != "WHITESPACE":
+ directive = "after_include"
+ else:
+ mo = PP_TOKEN_RE.match(file_contents, pos)
+ kind = mo.lastgroup
+
+ text = mo.group()
+ line = line_num
+ column = mo.start() - line_start
+ adj_line_start = 0
+ # only these kinds can contain a newline
+ if kind in ("WHITESPACE", "BLOCK_COMMENT", "LINE_COMMENT",
+ "STRING", "CHARCONST", "BAD_BLOCK_COM", "ESCNL"):
+ for tmo in ENDLINE_RE.finditer(text):
+ line_num += 1
+ adj_line_start = tmo.end()
+ if adj_line_start:
+ line_start = mo.start() + adj_line_start
+
+ # Track whether or not we are scanning a preprocessing directive.
+ if kind == "LINE_COMMENT" or (kind == "WHITESPACE" and adj_line_start):
+ at_bol = True
+ directive = None
+ else:
+ if kind == "PUNCTUATOR" and text == "#" and at_bol:
+ directive = "<null>"
+ elif kind == "IDENT" and directive == "<null>":
+ directive = text
+ at_bol = False
+
+ # Report ill-formed tokens and rewrite them as their well-formed
+ # equivalents, so downstream processing doesn't have to know about them.
+ # (Rewriting instead of discarding provides better error recovery.)
+ if kind == "BAD_BLOCK_COM":
+ reporter.error(Token("BAD_BLOCK_COM", "", line, column+1, ""),
+ "unclosed block comment")
+ text += "*/"
+ kind = "BLOCK_COMMENT"
+ elif kind == "BAD_STRING":
+ reporter.error(Token("BAD_STRING", "", line, column+1, ""),
+ "unclosed string")
+ text += "\""
+ kind = "STRING"
+ elif kind == "BAD_CHARCONST":
+ reporter.error(Token("BAD_CHARCONST", "", line, column+1, ""),
+ "unclosed char constant")
+ text += "'"
+ kind = "CHARCONST"
+
+ tok = Token(kind, text, line, column+1,
+ "include" if directive == "after_include" else directive)
+ # Do not complain about OTHER tokens inside macro definitions.
+ # $ and @ appear in macros defined by headers intended to be
+ # included from assembly language, e.g. sysdeps/mips/sys/asm.h.
+ if kind == "OTHER" and directive != "define":
+ self.error(tok, "stray {!r} in program")
+
+ yield tok
+ pos = mo.end()
+
+#
+# Base and generic classes for individual checks.
+#
+
+class ConstructChecker:
+ """Scan a stream of C preprocessing tokens and possibly report
+ problems with them. The REPORTER object passed to __init__ has
+ one method, reporter.error(token, message), which should be
+ called to indicate a problem detected at the position of TOKEN.
+ If MESSAGE contains the four-character sequence '{!r}' then that
+ will be replaced with a textual representation of TOKEN.
+ """
+ def __init__(self, reporter):
+ self.reporter = reporter
+
+ def examine(self, tok):
+ """Called once for each token in a header file.
+ Call self.reporter.error if a problem is detected.
+ """
+ raise NotImplementedError
+
+ def eof(self):
+ """Called once at the end of the stream. Subclasses need only
+ override this if it might have something to do."""
+ pass
+
+class NoCheck(ConstructChecker):
+ """Generic checker class which doesn't do anything. Substitute this
+ class for a real checker when a particular check should be skipped
+ for some file."""
+
+ def examine(self, tok):
+ pass
+
+#
+# Check for obsolete type names.
+#
+
+# The obsolete type names we're looking for:
+OBSOLETE_TYPE_RE_ = re.compile(r"""\A
+ (__)?
+ ( quad_t
+ | u(?: short | int | long
+ | _(?: char | short | int(?:[0-9]+_t)? | long | quad_t )))
+\Z""", re.VERBOSE)
+
+class ObsoleteNotAllowed(ConstructChecker):
+ """Don't allow any use of the obsolete typedefs."""
+ def examine(self, tok):
+ if OBSOLETE_TYPE_RE_.match(tok.text):
+ self.reporter.error(tok, "use of {!r}")
+
+class ObsoletePrivateDefinitionsAllowed(ConstructChecker):
+ """Allow definitions of the private versions of the
+ obsolete typedefs; that is, 'typedef [anything] __obsolete;'
+ """
+ def __init__(self, reporter):
+ super().__init__(reporter)
+ self.in_typedef = False
+ self.prev_token = None
+
+ def examine(self, tok):
+ # bits/types.h hides 'typedef' in a macro sometimes.
+ if (tok.kind == "IDENT"
+ and tok.text in ("typedef", "__STD_TYPE")
+ and tok.context is None):
+ self.in_typedef = True
+ elif tok.kind == "PUNCTUATOR" and tok.text == ";" and self.in_typedef:
+ self.in_typedef = False
+ if self.prev_token.kind == "IDENT":
+ m = OBSOLETE_TYPE_RE_.match(self.prev_token.text)
+ if m and m.group(1) != "__":
+ self.reporter.error(self.prev_token, "use of {!r}")
+ self.prev_token = None
+ else:
+ self._check_prev()
+
+ self.prev_token = tok
+
+ def eof(self):
+ self._check_prev()
+
+ def _check_prev(self):
+ if (self.prev_token is not None
+ and self.prev_token.kind == "IDENT"
+ and OBSOLETE_TYPE_RE_.match(self.prev_token.text)):
+ self.reporter.error(self.prev_token, "use of {!r}")
+
+class ObsoletePublicDefinitionsAllowed(ConstructChecker):
+ """Allow definitions of the public versions of the obsolete
+ typedefs. Only specific forms of definition are allowed:
+
+ typedef __obsolete obsolete; // identifiers must agree
+ typedef __uintN_t u_intN_t; // N must agree
+ typedef unsigned long int ulong;
+ typedef unsigned short int ushort;
+ typedef unsigned int uint;
+ """
+ def __init__(self, reporter):
+ super().__init__(reporter)
+ self.typedef_tokens = []
+
+ def examine(self, tok):
+ if tok.kind in ("WHITESPACE", "BLOCK_COMMENT",
+ "LINE_COMMENT", "NL", "ESCNL"):
+ pass
+
+ elif (tok.kind == "IDENT" and tok.text == "typedef"
+ and tok.context is None):
+ if self.typedef_tokens:
+ self.reporter.error(tok, "typedef inside typedef")
+ self._reset()
+ self.typedef_tokens.append(tok)
+
+ elif tok.kind == "PUNCTUATOR" and tok.text == ";":
+ self._finish()
+
+ elif self.typedef_tokens:
+ self.typedef_tokens.append(tok)
+
+ def eof(self):
+ self._reset()
+
+ def _reset(self):
+ while self.typedef_tokens:
+ tok = self.typedef_tokens.pop(0)
+ if tok.kind == "IDENT" and OBSOLETE_TYPE_RE_.match(tok.text):
+ self.reporter.error(tok, "use of {!r}")
+
+ def _finish(self):
+ if not self.typedef_tokens: return
+ if self.typedef_tokens[-1].kind == "IDENT":
+ m = OBSOLETE_TYPE_RE_.match(self.typedef_tokens[-1].text)
+ if m:
+ if self._permissible_public_definition(m):
+ self.typedef_tokens.clear()
+ self._reset()
+
+ def _permissible_public_definition(self, m):
+ if m.group(1) == "__": return False
+ name = m.group(2)
+ toks = self.typedef_tokens
+ ntok = len(toks)
+ if ntok == 3 and toks[1].kind == "IDENT":
+ defn = toks[1].text
+ n = OBSOLETE_TYPE_RE_.match(defn)
+ if n and n.group(1) == "__" and n.group(2) == name:
+ return True
+
+ if (name[:5] == "u_int" and name[-2:] == "_t"
+ and defn[:6] == "__uint" and defn[-2:] == "_t"
+ and name[5:-2] == defn[6:-2]):
+ return True
+
+ return False
+
+ if (name == "ulong" and ntok == 5
+ and toks[1].kind == "IDENT" and toks[1].text == "unsigned"
+ and toks[2].kind == "IDENT" and toks[2].text == "long"
+ and toks[3].kind == "IDENT" and toks[3].text == "int"):
+ return True
+
+ if (name == "ushort" and ntok == 5
+ and toks[1].kind == "IDENT" and toks[1].text == "unsigned"
+ and toks[2].kind == "IDENT" and toks[2].text == "short"
+ and toks[3].kind == "IDENT" and toks[3].text == "int"):
+ return True
+
+ if (name == "uint" and ntok == 4
+ and toks[1].kind == "IDENT" and toks[1].text == "unsigned"
+ and toks[2].kind == "IDENT" and toks[2].text == "int"):
+ return True
+
+ return False
+
+def ObsoleteTypedefChecker(reporter, fname):
+ """Factory: produce an instance of the appropriate
+ obsolete-typedef checker for FNAME."""
+
+ # The obsolete rpc/ and rpcsvc/ headers are allowed to use the
+ # obsolete types, because it would be more trouble than it's
+ # worth to remove them from headers that we intend to stop
+ # installing eventually anyway.
+ if (fname.startswith("rpc/")
+ or fname.startswith("rpcsvc/")
+ or "/rpc/" in fname
+ or "/rpcsvc/" in fname):
+ return NoCheck(reporter)
+
+ # bits/types.h is allowed to define the __-versions of the
+ # obsolete types.
+ if (fname == "bits/types.h"
+ or fname.endswith("/bits/types.h")):
+ return ObsoletePrivateDefinitionsAllowed(reporter)
+
+ # sys/types.h is allowed to use the __-versions of the
+ # obsolete types, but only to define the unprefixed versions.
+ if (fname == "sys/types.h"
+ or fname.endswith("/sys/types.h")):
+ return ObsoletePublicDefinitionsAllowed(reporter)
+
+ return ObsoleteNotAllowed(reporter)
+
+#
+# Master control
+#
+
+class HeaderChecker:
+ """Perform all of the checks on each header. This is also the
+ "reporter" object expected by tokenize_c and ConstructChecker.
+ """
+ def __init__(self):
+ self.fname = None
+ self.status = 0
+
+ def error(self, tok, message):
+ self.status = 1
+ if '{!r}' in message:
+ message = message.format(tok.text)
+ sys.stderr.write("{}:{}:{}: error: {}\n".format(
+ self.fname, tok.line, tok.column, message))
+
+ def check(self, fname):
+ self.fname = fname
+ try:
+ with open(fname, "rt") as fp:
+ contents = fp.read()
+ except OSError as e:
+ sys.stderr.write("{}: {}\n".format(fname, e.strerror))
+ self.status = 1
+ return
+
+ typedef_checker = ObsoleteTypedefChecker(self, self.fname)
+
+ for tok in tokenize_c(contents, self):
+ typedef_checker.examine(tok)
+
+def main():
+ ap = argparse.ArgumentParser(description=__doc__)
+ ap.add_argument("headers", metavar="header", nargs="+",
+ help="one or more headers to scan for obsolete constructs")
+ args = ap.parse_args()
+
+ checker = HeaderChecker()
+ for fname in args.headers:
+ # Headers whose installed name begins with "finclude/" contain
+ # Fortran, not C, and this program should completely ignore them.
+ if not (fname.startswith("finclude/") or "/finclude/" in fname):
+ checker.check(fname)
+ sys.exit(checker.status)
+
+main()
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
-/* This particular implementation was written by Eric Blake, 2008. */
-
#ifndef _LIBC
# include <config.h>
#endif
-/* Specification of memmem. */
#include <string.h>
#ifndef _LIBC
-# define __builtin_expect(expr, val) (expr)
# define __memmem memmem
#endif
#undef memmem
-/* Return the first occurrence of NEEDLE in HAYSTACK. Return HAYSTACK
- if NEEDLE_LEN is 0, otherwise NULL if NEEDLE is not found in
- HAYSTACK. */
+/* Hash character pairs so a small shift table can be used. All bits of
+ p[0] are included, but not all bits from p[-1]. So if two equal hashes
+ match on p[-1], p[0] matches too. Hash collisions are harmless and result
+ in smaller shifts. */
+#define hash2(p) (((size_t)(p)[0] - ((size_t)(p)[-1] << 3)) % sizeof (shift))
+
+/* Fast memmem algorithm with guaranteed linear-time performance.
+ Small needles up to size 2 use a dedicated linear search. Longer needles
+ up to size 256 use a novel modified Horspool algorithm. It hashes pairs
+ of characters to quickly skip past mismatches. The main search loop only
+ exits if the last 2 characters match, avoiding unnecessary calls to memcmp
+ and allowing for a larger skip if there is no match. A self-adapting
+ filtering check is used to quickly detect mismatches in long needles.
+ By limiting the needle length to 256, the shift table can be reduced to 8
+ bits per entry, lowering preprocessing overhead and minimizing cache effects.
+ The limit also implies worst-case performance is linear.
+ Needles larger than 256 characters use the linear-time Two-Way algorithm. */
void *
-__memmem (const void *haystack_start, size_t haystack_len,
- const void *needle_start, size_t needle_len)
+__memmem (const void *haystack, size_t hs_len,
+ const void *needle, size_t ne_len)
{
- /* Abstract memory is considered to be an array of 'unsigned char' values,
- not an array of 'char' values. See ISO C 99 section 6.2.6.1. */
- const unsigned char *haystack = (const unsigned char *) haystack_start;
- const unsigned char *needle = (const unsigned char *) needle_start;
-
- if (needle_len == 0)
- /* The first occurrence of the empty string is deemed to occur at
- the beginning of the string. */
- return (void *) haystack;
-
- /* Sanity check, otherwise the loop might search through the whole
- memory. */
- if (__glibc_unlikely (haystack_len < needle_len))
+ const unsigned char *hs = (const unsigned char *) haystack;
+ const unsigned char *ne = (const unsigned char *) needle;
+
+ if (ne_len == 0)
+ return (void *) hs;
+ if (ne_len == 1)
+ return (void *) memchr (hs, ne[0], hs_len);
+
+ /* Ensure haystack length is >= needle length. */
+ if (hs_len < ne_len)
return NULL;
- /* Use optimizations in memchr when possible, to reduce the search
- size of haystack using a linear algorithm with a smaller
- coefficient. However, avoid memchr for long needles, since we
- can often achieve sublinear performance. */
- if (needle_len < LONG_NEEDLE_THRESHOLD)
+ const unsigned char *end = hs + hs_len - ne_len;
+
+ if (ne_len == 2)
+ {
+ uint32_t nw = ne[0] << 16 | ne[1], hw = hs[0] << 16 | hs[1];
+ for (hs++; hs <= end && hw != nw; )
+ hw = hw << 16 | *++hs;
+ return hw == nw ? (void *)hs - 1 : NULL;
+ }
+
+ /* Use Two-Way algorithm for very long needles. */
+ if (__builtin_expect (ne_len > 256, 0))
+ return two_way_long_needle (hs, hs_len, ne, ne_len);
+
+ uint8_t shift[256];
+ size_t tmp, shift1;
+ size_t m1 = ne_len - 1;
+ size_t offset = 0;
+
+ memset (shift, 0, sizeof (shift));
+ for (int i = 1; i < m1; i++)
+ shift[hash2 (ne + i)] = i;
+ /* Shift1 is the amount we can skip after matching the hash of the
+ needle end but not the full needle. */
+ shift1 = m1 - shift[hash2 (ne + m1)];
+ shift[hash2 (ne + m1)] = m1;
+
+ for ( ; hs <= end; )
{
- haystack = memchr (haystack, *needle, haystack_len);
- if (!haystack || __builtin_expect (needle_len == 1, 0))
- return (void *) haystack;
- haystack_len -= haystack - (const unsigned char *) haystack_start;
- if (haystack_len < needle_len)
- return NULL;
- /* Check whether we have a match. This improves performance since we
- avoid the initialization overhead of the two-way algorithm. */
- if (memcmp (haystack, needle, needle_len) == 0)
- return (void *) haystack;
- return two_way_short_needle (haystack, haystack_len, needle, needle_len);
+ /* Skip past character pairs not in the needle. */
+ do
+ {
+ hs += m1;
+ tmp = shift[hash2 (hs)];
+ }
+ while (tmp == 0 && hs <= end);
+
+ /* If the match is not at the end of the needle, shift to the end
+ and continue until we match the hash of the needle end. */
+ hs -= tmp;
+ if (tmp < m1)
+ continue;
+
+ /* Hash of the last 2 characters matches. If the needle is long,
+ try to quickly filter out mismatches. */
+ if (m1 < 15 || memcmp (hs + offset, ne + offset, 8) == 0)
+ {
+ if (memcmp (hs, ne, m1) == 0)
+ return (void *) hs;
+
+ /* Adjust filter offset when it doesn't find the mismatch. */
+ offset = (offset >= 8 ? offset : m1) - 8;
+ }
+
+ /* Skip based on matching the hash of the needle end. */
+ hs += shift1;
}
- else
- return two_way_long_needle (haystack, haystack_len, needle, needle_len);
+ return NULL;
}
libc_hidden_def (__memmem)
weak_alias (__memmem, memmem)
libc_hidden_weak (memmem)
-
-#undef LONG_NEEDLE_THRESHOLD
most 2 * HAYSTACK_LEN - NEEDLE_LEN comparisons occur in searching.
If AVAILABLE modifies HAYSTACK_LEN (as in strstr), then at most 3 *
HAYSTACK_LEN - NEEDLE_LEN comparisons occur in searching. */
-static RETURN_TYPE
+static inline RETURN_TYPE
two_way_short_needle (const unsigned char *haystack, size_t haystack_len,
const unsigned char *needle, size_t needle_len)
{
and sublinear performance O(HAYSTACK_LEN / NEEDLE_LEN) is possible.
If AVAILABLE modifies HAYSTACK_LEN (as in strstr), then at most 3 *
HAYSTACK_LEN - NEEDLE_LEN comparisons occur in searching, and
- sublinear performance is not possible. */
-static RETURN_TYPE
+ sublinear performance is not possible.
+
+ Since this function is large and complex, block inlining to avoid
+ slowing down the common case of small needles. */
+__attribute__((noinline)) static RETURN_TYPE
two_way_long_needle (const unsigned char *haystack, size_t haystack_len,
const unsigned char *needle, size_t needle_len)
{
#include <stddef.h>
/* Tell the caller that we provide correct C++ prototypes. */
-#if defined __cplusplus && __GNUC_PREREQ (4, 4)
+#if defined __cplusplus && (__GNUC_PREREQ (4, 4) \
+ || __glibc_clang_prereq (3, 5))
# define __CORRECT_ISO_CPP_STRING_H_PROTO
#endif
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
-/* This particular implementation was written by Eric Blake, 2008. */
-
#ifndef _LIBC
# include <config.h>
#endif
-/* Specification of strstr. */
#include <string.h>
-#include <stdbool.h>
-
-#ifndef _LIBC
-# define __builtin_expect(expr, val) (expr)
-#endif
-
#define RETURN_TYPE char *
#define AVAILABLE(h, h_l, j, n_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))
#include "str-two-way.h"
#undef strstr
#define STRSTR strstr
#endif
-/* Return the first occurrence of NEEDLE in HAYSTACK. Return HAYSTACK
- if NEEDLE is empty, otherwise NULL if NEEDLE is not found in
- HAYSTACK. */
-char *
-STRSTR (const char *haystack, const char *needle)
+static inline char *
+strstr2 (const unsigned char *hs, const unsigned char *ne)
{
- size_t needle_len; /* Length of NEEDLE. */
- size_t haystack_len; /* Known minimum length of HAYSTACK. */
-
- /* Handle empty NEEDLE special case. */
- if (needle[0] == '\0')
- return (char *) haystack;
+ uint32_t h1 = (ne[0] << 16) | ne[1];
+ uint32_t h2 = 0;
+ for (int c = hs[0]; h1 != h2 && c != 0; c = *++hs)
+ h2 = (h2 << 16) | c;
+ return h1 == h2 ? (char *)hs - 2 : NULL;
+}
- /* Skip until we find the first matching char from NEEDLE. */
- haystack = strchr (haystack, needle[0]);
- if (haystack == NULL || needle[1] == '\0')
- return (char *) haystack;
+static inline char *
+strstr3 (const unsigned char *hs, const unsigned char *ne)
+{
+ uint32_t h1 = ((uint32_t)ne[0] << 24) | (ne[1] << 16) | (ne[2] << 8);
+ uint32_t h2 = 0;
+ for (int c = hs[0]; h1 != h2 && c != 0; c = *++hs)
+ h2 = (h2 | c) << 8;
+ return h1 == h2 ? (char *)hs - 3 : NULL;
+}
- /* Ensure HAYSTACK length is at least as long as NEEDLE length.
- Since a match may occur early on in a huge HAYSTACK, use strnlen
+/* Hash character pairs so a small shift table can be used. All bits of
+ p[0] are included, but not all bits from p[-1]. So if two equal hashes
+ match on p[-1], p[0] matches too. Hash collisions are harmless and result
+ in smaller shifts. */
+#define hash2(p) (((size_t)(p)[0] - ((size_t)(p)[-1] << 3)) % sizeof (shift))
+
+/* Fast strstr algorithm with guaranteed linear-time performance.
+ Small needles up to size 3 use a dedicated linear search. Longer needles
+ up to size 256 use a novel modified Horspool algorithm. It hashes pairs
+ of characters to quickly skip past mismatches. The main search loop only
+ exits if the last 2 characters match, avoiding unnecessary calls to memcmp
+ and allowing for a larger skip if there is no match. A self-adapting
+ filtering check is used to quickly detect mismatches in long needles.
+ By limiting the needle length to 256, the shift table can be reduced to 8
+ bits per entry, lowering preprocessing overhead and minimizing cache effects.
+ The limit also implies worst-case performance is linear.
+ Needles larger than 256 characters use the linear-time Two-Way algorithm. */
+char *
+STRSTR (const char *haystack, const char *needle)
+{
+ const unsigned char *hs = (const unsigned char *) haystack;
+ const unsigned char *ne = (const unsigned char *) needle;
+
+ /* Handle short needle special cases first. */
+ if (ne[0] == '\0')
+ return (char *)hs;
+ hs = (const unsigned char *)strchr ((const char*)hs, ne[0]);
+ if (hs == NULL || ne[1] == '\0')
+ return (char*)hs;
+ if (ne[2] == '\0')
+ return strstr2 (hs, ne);
+ if (ne[3] == '\0')
+ return strstr3 (hs, ne);
+
+ /* Ensure haystack length is at least as long as needle length.
+ Since a match may occur early on in a huge haystack, use strnlen
and read ahead a few cachelines for improved performance. */
- needle_len = strlen (needle);
- haystack_len = __strnlen (haystack, needle_len + 256);
- if (haystack_len < needle_len)
+ size_t ne_len = strlen ((const char*)ne);
+ size_t hs_len = __strnlen ((const char*)hs, ne_len | 512);
+ if (hs_len < ne_len)
return NULL;
- /* Check whether we have a match. This improves performance since we avoid
- the initialization overhead of the two-way algorithm. */
- if (memcmp (haystack, needle, needle_len) == 0)
- return (char *) haystack;
-
- /* Perform the search. Abstract memory is considered to be an array
- of 'unsigned char' values, not an array of 'char' values. See
- ISO C 99 section 6.2.6.1. */
- if (needle_len < LONG_NEEDLE_THRESHOLD)
- return two_way_short_needle ((const unsigned char *) haystack,
- haystack_len,
- (const unsigned char *) needle, needle_len);
- return two_way_long_needle ((const unsigned char *) haystack, haystack_len,
- (const unsigned char *) needle, needle_len);
+ /* Check whether we have a match. This improves performance since we
+ avoid initialization overheads. */
+ if (memcmp (hs, ne, ne_len) == 0)
+ return (char *) hs;
+
+ /* Use Two-Way algorithm for very long needles. */
+ if (__glibc_unlikely (ne_len > 256))
+ return two_way_long_needle (hs, hs_len, ne, ne_len);
+
+ const unsigned char *end = hs + hs_len - ne_len;
+ uint8_t shift[256];
+ size_t tmp, shift1;
+ size_t m1 = ne_len - 1;
+ size_t offset = 0;
+
+ /* Initialize bad character shift hash table. */
+ memset (shift, 0, sizeof (shift));
+ for (int i = 1; i < m1; i++)
+ shift[hash2 (ne + i)] = i;
+ /* Shift1 is the amount we can skip after matching the hash of the
+ needle end but not the full needle. */
+ shift1 = m1 - shift[hash2 (ne + m1)];
+ shift[hash2 (ne + m1)] = m1;
+
+ while (1)
+ {
+ if (__glibc_unlikely (hs > end))
+ {
+ end += __strnlen ((const char*)end + m1 + 1, 2048);
+ if (hs > end)
+ return NULL;
+ }
+
+ /* Skip past character pairs not in the needle. */
+ do
+ {
+ hs += m1;
+ tmp = shift[hash2 (hs)];
+ }
+ while (tmp == 0 && hs <= end);
+
+ /* If the match is not at the end of the needle, shift to the end
+ and continue until we match the hash of the needle end. */
+ hs -= tmp;
+ if (tmp < m1)
+ continue;
+
+ /* Hash of the last 2 characters matches. If the needle is long,
+ try to quickly filter out mismatches. */
+ if (m1 < 15 || memcmp (hs + offset, ne + offset, 8) == 0)
+ {
+ if (memcmp (hs, ne, m1) == 0)
+ return (void *) hs;
+
+ /* Adjust filter offset when it doesn't find the mismatch. */
+ offset = (offset >= 8 ? offset : m1) - 8;
+ }
+
+ /* Skip based on matching the hash of the needle end. */
+ hs += shift1;
+ }
}
libc_hidden_builtin_def (strstr)
-
-#undef LONG_NEEDLE_THRESHOLD
support_record_failure \
support_run_diff \
support_shared_allocate \
+ support_subprocess \
support_test_compare_blob \
support_test_compare_failure \
support_test_compare_string \
xopen \
xpipe \
xpoll \
+ xposix_memalign \
xpthread_attr_destroy \
xpthread_attr_init \
xpthread_attr_setdetachstate \
xpthread_attr_setguardsize \
+ xpthread_attr_setstack \
xpthread_attr_setstacksize \
xpthread_barrier_destroy \
xpthread_barrier_init \
xpthread_mutexattr_settype \
xpthread_once \
xpthread_rwlock_init \
+ xpthread_rwlock_destroy \
xpthread_rwlock_rdlock \
xpthread_rwlock_unlock \
xpthread_rwlock_wrlock \
xsignal \
xsigstack \
xsocket \
+ xposix_spawn \
+ xposix_spawn_file_actions_addclose \
+ xposix_spawn_file_actions_adddup2 \
xstrdup \
xstrndup \
xsymlink \
-DOBJDIR_PATH=\"`cd $(objpfx)/..; pwd`\" \
-DOBJDIR_ELF_LDSO_PATH=\"`cd $(objpfx)/..; pwd`/elf/$(rtld-installed-name)\" \
-DINSTDIR_PATH=\"$(prefix)\" \
- -DLIBDIR_PATH=\"$(libdir)\"
+ -DLIBDIR_PATH=\"$(libdir)\" \
+ -DBINDIR_PATH=\"$(bindir)\"
ifeq (,$(CXX))
LINKS_DSO_PROGRAM = links-dso-program-c
LDLIBS-links-dso-program = -lstdc++ -lgcc -lgcc_s $(libunwind)
endif
+ifeq (yes,$(have-selinux))
+LDLIBS-$(LINKS_DSO_PROGRAM) += -lselinux
+endif
+
+
LDLIBS-test-container = $(libsupport)
others += test-container
$(objpfx)tst-support_format_dns_packet: $(common-objpfx)resolv/libresolv.so
+tst-support_capture_subprocess-ARGS = -- $(host-test-program-cmd)
+
include ../Rules
struct support_capture_subprocess support_capture_subprocess
(void (*callback) (void *), void *closure);
+/* Issue FILE with ARGV arguments by using posix_spawn and capture standard
+ output, standard error, and the exit status. The out.buffer and err.buffer
+ are handle as support_capture_subprocess. */
+struct support_capture_subprocess support_capture_subprogram
+ (const char *file, char *const argv[]);
+
/* Deallocate the subprocess data captured by
support_capture_subprocess. */
void support_capture_subprocess_free (struct support_capture_subprocess *);
#include <stdio.h>
+/* makedb needs selinux dso's. */
+#ifdef HAVE_SELINUX
+# include <selinux/selinux.h>
+#endif
+
+/* The purpose of this file is to indicate to the build system which
+ shared objects need to be copied into the testroot, such as gcc or
+ selinux support libraries. This program is never executed, only
+ scanned for dependencies on shared objects, so the code below may
+ seem weird - it's written to survive gcc optimization and force
+ such dependencies.
+*/
+
int
main (int argc, char **argv)
{
/* Complexity to keep gcc from optimizing this away. */
printf ("This is a test %s.\n", argc > 1 ? argv[1] : "null");
+#ifdef HAVE_SELINUX
+ /* This exists to force libselinux.so to be required. */
+ printf ("selinux %d\n", is_selinux_enabled ());
+#endif
return 0;
}
#include <iostream>
+/* makedb needs selinux dso's. */
+#ifdef HAVE_SELINUX
+# include <selinux/selinux.h>
+#endif
+
using namespace std;
+/* The purpose of this file is to indicate to the build system which
+ shared objects need to be copied into the testroot, such as gcc or
+ selinux support libraries. This program is never executed, only
+ scanned for dependencies on shared objects, so the code below may
+ seem weird - it's written to survive gcc optimization and force
+ such dependencies.
+*/
+
int
main (int argc, char **argv)
{
/* Complexity to keep gcc from optimizing this away. */
cout << (argc > 1 ? argv[1] : "null");
+#ifdef HAVE_SELINUX
+ /* This exists to force libselinux.so to be required. */
+ cout << "selinux " << is_selinux_enabled ();
+#endif
return 0;
}
--- /dev/null
+/* Create a subprocess.
+ 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 SUPPORT_SUBPROCESS_H
+#define SUPPORT_SUBPROCESS_H
+
+#include <sys/types.h>
+
+struct support_subprocess
+{
+ int stdout_pipe[2];
+ int stderr_pipe[2];
+ pid_t pid;
+};
+
+/* Invoke CALLBACK (CLOSURE) in a subprocess created with fork and return
+ its PID, a pipe redirected to STDOUT, and a pipe redirected to STDERR. */
+struct support_subprocess support_subprocess
+ (void (*callback) (void *), void *closure);
+
+/* Issue FILE with ARGV arguments by using posix_spawn and return is PID, a
+ pipe redirected to STDOUT, and a pipe redirected to STDERR. */
+struct support_subprocess support_subprogram
+ (const char *file, char *const argv[]);
+
+/* Wait for the subprocess indicated by PROC::PID. Return the status
+ indicate by waitpid call. */
+int support_process_wait (struct support_subprocess *proc);
+
+/* Terminate the subprocess indicated by PROC::PID, first with a SIGTERM and
+ then with a SIGKILL. Return the status as for waitpid call. */
+int support_process_terminate (struct support_subprocess *proc);
+
+#endif
void *xmalloc (size_t) __attribute__ ((malloc));
void *xcalloc (size_t n, size_t s) __attribute__ ((malloc));
void *xrealloc (void *p, size_t n);
+void *xposix_memalign (size_t alignment, size_t n);
char *xasprintf (const char *format, ...)
__attribute__ ((format (printf, 1, 2), malloc));
char *xstrdup (const char *);
extern const char support_install_prefix[];
/* Corresponds to the install's lib/ or lib64/ directory. */
extern const char support_libdir_prefix[];
+/* Corresponds to the install's bin/ directory. */
+extern const char support_bindir_prefix[];
extern ssize_t support_copy_file_range (int, off64_t *, int, off64_t *,
size_t, unsigned int);
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
+#include <support/subprocess.h>
#include <support/capture_subprocess.h>
#include <errno.h>
#include <support/check.h>
#include <support/xunistd.h>
#include <support/xsocket.h>
+#include <support/xspawn.h>
static void
transfer (const char *what, struct pollfd *pfd, struct xmemstream *stream)
}
}
-struct support_capture_subprocess
-support_capture_subprocess (void (*callback) (void *), void *closure)
+static void
+support_capture_poll (struct support_capture_subprocess *result,
+ struct support_subprocess *proc)
{
- struct support_capture_subprocess result;
- xopen_memstream (&result.out);
- xopen_memstream (&result.err);
-
- 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);
-
- pid_t pid = xfork ();
- if (pid == 0)
- {
- xclose (stdout_pipe[0]);
- xclose (stderr_pipe[0]);
- xdup2 (stdout_pipe[1], STDOUT_FILENO);
- xdup2 (stderr_pipe[1], STDERR_FILENO);
- xclose (stdout_pipe[1]);
- xclose (stderr_pipe[1]);
- callback (closure);
- _exit (0);
- }
- xclose (stdout_pipe[1]);
- xclose (stderr_pipe[1]);
-
struct pollfd fds[2] =
{
- { .fd = stdout_pipe[0], .events = POLLIN },
- { .fd = stderr_pipe[0], .events = POLLIN },
+ { .fd = proc->stdout_pipe[0], .events = POLLIN },
+ { .fd = proc->stderr_pipe[0], .events = POLLIN },
};
do
{
xpoll (fds, 2, -1);
- transfer ("stdout", &fds[0], &result.out);
- transfer ("stderr", &fds[1], &result.err);
+ transfer ("stdout", &fds[0], &result->out);
+ transfer ("stderr", &fds[1], &result->err);
}
while (fds[0].events != 0 || fds[1].events != 0);
- xclose (stdout_pipe[0]);
- xclose (stderr_pipe[0]);
- xfclose_memstream (&result.out);
- xfclose_memstream (&result.err);
- xwaitpid (pid, &result.status, 0);
+ xfclose_memstream (&result->out);
+ xfclose_memstream (&result->err);
+
+ result->status = support_process_wait (proc);
+}
+
+struct support_capture_subprocess
+support_capture_subprocess (void (*callback) (void *), void *closure)
+{
+ struct support_capture_subprocess result;
+ xopen_memstream (&result.out);
+ xopen_memstream (&result.err);
+
+ struct support_subprocess proc = support_subprocess (callback, closure);
+
+ support_capture_poll (&result, &proc);
+ return result;
+}
+
+struct support_capture_subprocess
+support_capture_subprogram (const char *file, char *const argv[])
+{
+ struct support_capture_subprocess result;
+ xopen_memstream (&result.out);
+ xopen_memstream (&result.err);
+
+ struct support_subprocess proc = support_subprogram (file, argv);
+
+ support_capture_poll (&result, &proc);
return result;
}
#else
# error please -DLIBDIR_PATH=something in the Makefile
#endif
+
+#ifdef BINDIR_PATH
+/* Corresponds to the install's bin/ directory. */
+const char support_bindir_prefix[] = BINDIR_PATH;
+#else
+# error please -DBINDIR_PATH=something in the Makefile
+#endif
--- /dev/null
+/* Create subprocess.
+ 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 <stdio.h>
+#include <signal.h>
+#include <time.h>
+#include <sys/wait.h>
+#include <stdbool.h>
+#include <support/xspawn.h>
+#include <support/check.h>
+#include <support/xunistd.h>
+#include <support/subprocess.h>
+
+static struct support_subprocess
+support_suprocess_init (void)
+{
+ struct support_subprocess result;
+
+ xpipe (result.stdout_pipe);
+ TEST_VERIFY (result.stdout_pipe[0] > STDERR_FILENO);
+ TEST_VERIFY (result.stdout_pipe[1] > STDERR_FILENO);
+
+ xpipe (result.stderr_pipe);
+ TEST_VERIFY (result.stderr_pipe[0] > STDERR_FILENO);
+ TEST_VERIFY (result.stderr_pipe[1] > STDERR_FILENO);
+
+ TEST_VERIFY (fflush (stdout) == 0);
+ TEST_VERIFY (fflush (stderr) == 0);
+
+ return result;
+}
+
+struct support_subprocess
+support_subprocess (void (*callback) (void *), void *closure)
+{
+ struct support_subprocess result = support_suprocess_init ();
+
+ result.pid = xfork ();
+ if (result.pid == 0)
+ {
+ xclose (result.stdout_pipe[0]);
+ xclose (result.stderr_pipe[0]);
+ xdup2 (result.stdout_pipe[1], STDOUT_FILENO);
+ xdup2 (result.stderr_pipe[1], STDERR_FILENO);
+ xclose (result.stdout_pipe[1]);
+ xclose (result.stderr_pipe[1]);
+ callback (closure);
+ _exit (0);
+ }
+ xclose (result.stdout_pipe[1]);
+ xclose (result.stderr_pipe[1]);
+
+ return result;
+}
+
+struct support_subprocess
+support_subprogram (const char *file, char *const argv[])
+{
+ struct support_subprocess result = support_suprocess_init ();
+
+ posix_spawn_file_actions_t fa;
+ /* posix_spawn_file_actions_init does not fail. */
+ posix_spawn_file_actions_init (&fa);
+
+ xposix_spawn_file_actions_addclose (&fa, result.stdout_pipe[0]);
+ xposix_spawn_file_actions_addclose (&fa, result.stderr_pipe[0]);
+ xposix_spawn_file_actions_adddup2 (&fa, result.stdout_pipe[1], STDOUT_FILENO);
+ xposix_spawn_file_actions_adddup2 (&fa, result.stderr_pipe[1], STDERR_FILENO);
+ xposix_spawn_file_actions_addclose (&fa, result.stdout_pipe[1]);
+ xposix_spawn_file_actions_addclose (&fa, result.stderr_pipe[1]);
+
+ result.pid = xposix_spawn (file, &fa, NULL, argv, NULL);
+
+ xclose (result.stdout_pipe[1]);
+ xclose (result.stderr_pipe[1]);
+
+ return result;
+}
+
+int
+support_process_wait (struct support_subprocess *proc)
+{
+ xclose (proc->stdout_pipe[0]);
+ xclose (proc->stderr_pipe[0]);
+
+ int status;
+ xwaitpid (proc->pid, &status, 0);
+ return status;
+}
+
+
+static bool
+support_process_kill (int pid, int signo, int *status)
+{
+ /* Kill the whole process group. */
+ kill (-pid, signo);
+ /* In case setpgid failed in the child, kill it individually too. */
+ kill (pid, signo);
+
+ /* Wait for it to terminate. */
+ pid_t killed;
+ for (int i = 0; i < 5; ++i)
+ {
+ int status;
+ killed = xwaitpid (pid, &status, WNOHANG|WUNTRACED);
+ if (killed != 0)
+ break;
+
+ /* Delay, give the system time to process the kill. If the
+ nanosleep() call return prematurely, all the better. We
+ won't restart it since this probably means the child process
+ finally died. */
+ nanosleep (&((struct timespec) { 0, 100000000 }), NULL);
+ }
+ if (killed != 0 && killed != pid)
+ return false;
+
+ return true;
+}
+
+int
+support_process_terminate (struct support_subprocess *proc)
+{
+ xclose (proc->stdout_pipe[0]);
+ xclose (proc->stderr_pipe[0]);
+
+ int status;
+ pid_t killed = xwaitpid (proc->pid, &status, WNOHANG|WUNTRACED);
+ if (killed != 0 && killed == proc->pid)
+ return status;
+
+ /* Subprocess is still running, terminate it. */
+ if (!support_process_kill (proc->pid, SIGTERM, &status) )
+ support_process_kill (proc->pid, SIGKILL, &status);
+
+ return status;
+}
#include <support/capture_subprocess.h>
#include <support/check.h>
#include <support/support.h>
+#include <support/temp_file.h>
#include <sys/wait.h>
#include <unistd.h>
+#include <paths.h>
+#include <getopt.h>
+#include <limits.h>
+#include <errno.h>
+#include <array_length.h>
+
+/* Nonzero if the program gets called via 'exec'. */
+static int restart;
+
+/* Hold the four initial argument used to respawn the process. */
+static char *initial_argv[5];
/* Write one byte at *P to FD and advance *P. Do nothing if *P is
'\0'. */
enum write_mode { out_first, err_first, interleave,
write_mode_last = interleave };
+static const char *
+write_mode_to_str (enum write_mode mode)
+{
+ switch (mode)
+ {
+ case out_first: return "out_first";
+ case err_first: return "err_first";
+ case interleave: return "interleave";
+ default: return "write_mode_last";
+ }
+}
+
+static enum write_mode
+str_to_write_mode (const char *mode)
+{
+ if (strcmp (mode, "out_first") == 0)
+ return out_first;
+ else if (strcmp (mode, "err_first") == 0)
+ return err_first;
+ else if (strcmp (mode, "interleave") == 0)
+ return interleave;
+ return write_mode_last;
+}
+
/* Describe what to write in the subprocess. */
struct test
{
int status;
};
-/* For use with support_capture_subprocess. */
-static void
-callback (void *closure)
+_Noreturn static void
+test_common (const struct test *test)
{
- const struct test *test = closure;
bool mode_ok = false;
switch (test->write_mode)
{
exit (test->status);
}
+static int
+parse_int (const char *str)
+{
+ char *endptr;
+ long int ret = strtol (str, &endptr, 10);
+ TEST_COMPARE (errno, 0);
+ TEST_VERIFY (ret >= 0 && ret <= INT_MAX);
+ return ret;
+}
+
+/* For use with support_capture_subprogram. */
+_Noreturn static void
+handle_restart (char *out, char *err, const char *write_mode,
+ const char *signal, const char *status)
+{
+ struct test test =
+ {
+ out,
+ err,
+ str_to_write_mode (write_mode),
+ parse_int (signal),
+ parse_int (status)
+ };
+ test_common (&test);
+}
+
+/* For use with support_capture_subprocess. */
+_Noreturn static void
+callback (void *closure)
+{
+ const struct test *test = closure;
+ test_common (test);
+}
+
/* Create a heap-allocated random string of letters. */
static char *
random_string (size_t length)
}
}
+static struct support_capture_subprocess
+do_subprocess (struct test *test)
+{
+ return support_capture_subprocess (callback, test);
+}
+
+static struct support_capture_subprocess
+do_subprogram (const struct test *test)
+{
+ /* Three digits per byte plus null terminator. */
+ char signalstr[3 * sizeof(int) + 1];
+ snprintf (signalstr, sizeof (signalstr), "%d", test->signal);
+ char statusstr[3 * sizeof(int) + 1];
+ snprintf (statusstr, sizeof (statusstr), "%d", test->status);
+
+ int argc = 0;
+ enum {
+ /* 4 elements from initial_argv (path to ld.so, '--library-path', the
+ path', and application name'), 2 for restart argument ('--direct',
+ '--restart'), 5 arguments plus NULL. */
+ argv_size = 12
+ };
+ char *args[argv_size];
+
+ for (char **arg = initial_argv; *arg != NULL; arg++)
+ args[argc++] = *arg;
+
+ args[argc++] = (char*) "--direct";
+ args[argc++] = (char*) "--restart";
+
+ args[argc++] = test->out;
+ args[argc++] = test->err;
+ args[argc++] = (char*) write_mode_to_str (test->write_mode);
+ args[argc++] = signalstr;
+ args[argc++] = statusstr;
+ args[argc] = NULL;
+ TEST_VERIFY (argc < argv_size);
+
+ return support_capture_subprogram (args[0], args);
+}
+
+enum test_type
+{
+ subprocess,
+ subprogram,
+};
+
static int
-do_test (void)
+do_multiple_tests (enum test_type type)
{
const int lengths[] = {0, 1, 17, 512, 20000, -1};
- /* Test multiple combinations of support_capture_subprocess.
+ /* Test multiple combinations of support_capture_sub{process,program}.
length_idx_stdout: Index into the lengths array above,
controls how many bytes are written by the subprocess to
TEST_VERIFY (strlen (test.out) == lengths[length_idx_stdout]);
TEST_VERIFY (strlen (test.err) == lengths[length_idx_stderr]);
- struct support_capture_subprocess result
- = support_capture_subprocess (callback, &test);
+ struct support_capture_subprocess result
+ = type == subprocess ? do_subprocess (&test)
+ : do_subprogram (&test);
+
check_stream ("stdout", &result.out, test.out);
check_stream ("stderr", &result.err, test.err);
return 0;
}
+static int
+do_test (int argc, char *argv[])
+{
+ /* We must have either:
+
+ - one or four parameters if called initially:
+ + argv[1]: path for ld.so optional
+ + argv[2]: "--library-path" optional
+ + argv[3]: the library path optional
+ + argv[4]: the application name
+
+ - six parameters left if called through re-execution:
+ + argv[1]: the application name
+ + argv[2]: the stdout to print
+ + argv[3]: the stderr to print
+ + argv[4]: the write mode to use
+ + argv[5]: the signal to issue
+ + argv[6]: the exit status code to use
+
+ * When built with --enable-hardcoded-path-in-tests or issued without
+ using the loader directly.
+ */
+
+ if (argc != (restart ? 6 : 5) && argc != (restart ? 6 : 2))
+ FAIL_EXIT1 ("wrong number of arguments (%d)", argc);
+
+ if (restart)
+ {
+ handle_restart (argv[1], /* stdout */
+ argv[2], /* stderr */
+ argv[3], /* write_mode */
+ argv[4], /* signal */
+ argv[5]); /* status */
+ }
+
+ initial_argv[0] = argv[1]; /* path for ld.so */
+ initial_argv[1] = argv[2]; /* "--library-path" */
+ initial_argv[2] = argv[3]; /* the library path */
+ initial_argv[3] = argv[4]; /* the application name */
+ initial_argv[4] = NULL;
+
+ do_multiple_tests (subprocess);
+ do_multiple_tests (subprogram);
+
+ return 0;
+}
+
+#define CMDLINE_OPTIONS \
+ { "restart", no_argument, &restart, 1 },
+#define TEST_FUNCTION_ARGV do_test
#include <support/test-driver.c>
--- /dev/null
+/* Error-checking wrapper for posix_memalign.
+ 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/support.h>
+#include <stdlib.h>
+#include <errno.h>
+
+void *
+xposix_memalign (size_t alignment, size_t n)
+{
+ void *p = NULL;
+
+ int ret = posix_memalign (&p, alignment, n);
+ if (ret)
+ {
+ errno = ret;
+ oom_error ("posix_memalign", n);
+ }
+ return p;
+}
--- /dev/null
+/* xposix_spawn implementation.
+ 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/xspawn.h>
+#include <support/check.h>
+
+pid_t
+xposix_spawn (const char *file, const posix_spawn_file_actions_t *fa,
+ const posix_spawnattr_t *attr, char *const args[],
+ char *const envp[])
+{
+ pid_t pid;
+ int status = posix_spawn (&pid, file, fa, attr, args, envp);
+ if (status != 0)
+ FAIL_EXIT1 ("posix_spawn to %s file failed: %m", file);
+ return pid;
+}
--- /dev/null
+/* xposix_spawn_file_actions_addclose implementation.
+ 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/xspawn.h>
+#include <support/check.h>
+
+int
+xposix_spawn_file_actions_addclose (posix_spawn_file_actions_t *fa, int fd)
+{
+ int status = posix_spawn_file_actions_addclose (fa, fd);
+ if (status == -1)
+ FAIL_EXIT1 ("posix_spawn_file_actions_addclose failed: %m\n");
+ return status;
+}
--- /dev/null
+/* xposix_spawn_file_actions_adddup2 implementation.
+ 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/xspawn.h>
+#include <support/check.h>
+
+int
+xposix_spawn_file_actions_adddup2 (posix_spawn_file_actions_t *fa, int fd,
+ int newfd)
+{
+ int status = posix_spawn_file_actions_adddup2 (fa, fd, newfd);
+ if (status == -1)
+ FAIL_EXIT1 ("posix_spawn_file_actions_adddup2 failed: %m\n");
+ return status;
+}
--- /dev/null
+/* pthread_attr_setstack 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_attr_setstack (pthread_attr_t *attr, void *stackaddr, size_t stacksize)
+{
+ xpthread_check_return ("pthread_attr_setstack",
+ pthread_attr_setstack (attr, stackaddr, stacksize));
+}
--- /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));
+}
--- /dev/null
+/* posix_spawn with support checks.
+ 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 SUPPORT_XSPAWN_H
+#define SUPPORT_XSPAWN_H
+
+#include <spawn.h>
+
+__BEGIN_DECLS
+
+int xposix_spawn_file_actions_addclose (posix_spawn_file_actions_t *, int);
+int xposix_spawn_file_actions_adddup2 (posix_spawn_file_actions_t *, int, int);
+
+pid_t xposix_spawn (const char *, const posix_spawn_file_actions_t *,
+ const posix_spawnattr_t *, char *const [], char *const []);
+
+__END_DECLS
+
+#endif
void xpthread_attr_init (pthread_attr_t *attr);
void xpthread_attr_setdetachstate (pthread_attr_t *attr,
int detachstate);
+void xpthread_attr_setstack (pthread_attr_t *attr, void *stackaddr,
+ size_t stacksize);
void xpthread_attr_setstacksize (pthread_attr_t *attr,
size_t stacksize);
void xpthread_attr_setguardsize (pthread_attr_t *attr,
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
/* Check for unexpected PLT reloc type. */
if (__builtin_expect (r_type == AARCH64_R(JUMP_SLOT), 1))
{
- if (__builtin_expect (map->l_mach.plt, 0) == 0)
- *reloc_addr += l_addr;
- else
- *reloc_addr = map->l_mach.plt;
+ if (map->l_mach.plt == 0)
+ {
+ /* Prelinking. */
+ *reloc_addr += l_addr;
+ return;
+ }
+
+ if (1) /* DT_AARCH64_VARIANT_PCS is not available, so always check. */
+ {
+ /* Check the symbol table for variant PCS symbols. */
+ const Elf_Symndx symndx = ELFW (R_SYM) (reloc->r_info);
+ const ElfW (Sym) *symtab =
+ (const void *)D_PTR (map, l_info[DT_SYMTAB]);
+ const ElfW (Sym) *sym = &symtab[symndx];
+ if (__glibc_unlikely (sym->st_other & STO_AARCH64_VARIANT_PCS))
+ {
+ /* Avoid lazy resolution of variant PCS symbols. */
+ const struct r_found_version *version = NULL;
+ if (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
+ {
+ const ElfW (Half) *vernum =
+ (const void *)D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
+ version = &map->l_versions[vernum[symndx] & 0x7fff];
+ }
+ elf_machine_rela (map, reloc, sym, version, reloc_addr,
+ skip_ifunc);
+ return;
+ }
+ }
+
+ *reloc_addr = map->l_mach.plt;
}
else if (__builtin_expect (r_type == AARCH64_R(TLSDESC), 1))
{
ldouble: 1
Function: Real part of "cpow_downward":
-double: 2
-float: 4
-idouble: 2
-ifloat: 4
+double: 5
+float: 8
+idouble: 5
+ifloat: 8
ildouble: 6
ldouble: 6
ldouble: 2
Function: Real part of "cpow_towardzero":
-double: 2
-float: 4
-idouble: 2
-ifloat: 4
+double: 5
+float: 8
+idouble: 5
+ifloat: 8
ildouble: 6
ldouble: 6
--- /dev/null
+/* Macros for customizing Systemtap <sys/sdt.h>. Arm version.
+ 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/>. */
+
+/* The default "nor" constraint produces unparseable memory references
+ for constants. Omit the problematic "o" constraint. See bug 24164
+ and GCC PR 89146. */
+#define STAP_SDT_ARG_CONSTRAINT nr
--- /dev/null
+/* As default architectures with sizeof (off_t) < sizeof (off64_t) the mmap is
+ implemented with __SYS_mmap2 syscall and the offset is represented in
+ multiples of page size. For offset larger than
+ '1 << (page_shift + 8 * sizeof (off_t))' (that is, 1<<44 on system with
+ page size of 4096 bytes) the system call silently truncates the offset.
+ For this case, glibc mmap implementation returns EINVAL. */
+
+/* Return the maximum value expected as offset argument in mmap64 call. */
+static inline uint64_t
+mmap64_maximum_offset (long int page_shift)
+{
+ if (sizeof (off_t) < sizeof (off64_t))
+ return (UINT64_C(1) << (page_shift + (8 * sizeof (off_t)))) - 1;
+ else
+ return UINT64_MAX;
+}
--- /dev/null
+/* Macros for customizing Systemtap <sys/sdt.h>. Generic version.
+ 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/>. */
+
+/* By default, there are no customizations. */
ifloat: 1
Function: Imaginary part of "ccos_downward":
-double: 2
+double: 3
float: 3
-idouble: 2
+idouble: 3
ifloat: 3
Function: Real part of "ccos_towardzero":
ifloat: 2
Function: Imaginary part of "ccos_towardzero":
-double: 2
+double: 3
float: 3
-idouble: 2
+idouble: 3
ifloat: 3
Function: Real part of "ccos_upward":
ifloat: 1
Function: Real part of "ccosh_downward":
-double: 1
+double: 2
float: 3
-idouble: 1
+idouble: 2
ifloat: 3
Function: Imaginary part of "ccosh_downward":
-double: 2
+double: 3
float: 3
-idouble: 2
+idouble: 3
ifloat: 3
Function: Real part of "ccosh_towardzero":
-double: 1
+double: 2
float: 3
-idouble: 1
+idouble: 2
ifloat: 3
Function: Imaginary part of "ccosh_towardzero":
-double: 2
+double: 3
float: 3
-idouble: 2
+idouble: 3
ifloat: 3
Function: Real part of "ccosh_upward":
ifloat: 2
Function: Real part of "cexp_downward":
-double: 1
+double: 2
float: 2
-idouble: 1
+idouble: 2
ifloat: 2
Function: Imaginary part of "cexp_downward":
-double: 1
+double: 3
float: 3
-idouble: 1
+idouble: 3
ifloat: 3
Function: Real part of "cexp_towardzero":
-double: 1
+double: 2
float: 2
-idouble: 1
+idouble: 2
ifloat: 2
Function: Imaginary part of "cexp_towardzero":
-double: 1
+double: 3
float: 3
-idouble: 1
+idouble: 3
ifloat: 3
Function: Real part of "cexp_upward":
ifloat: 2
Function: Imaginary part of "cexp_upward":
-double: 1
+double: 3
float: 2
-idouble: 1
+idouble: 3
ifloat: 2
Function: Real part of "clog":
ifloat: 1
Function: "cosh_downward":
-double: 1
+double: 2
float: 1
-idouble: 1
+idouble: 2
ifloat: 1
Function: "cosh_towardzero":
-double: 1
+double: 2
float: 1
-idouble: 1
+idouble: 2
ifloat: 1
Function: "cosh_upward":
-double: 1
+double: 2
float: 2
-idouble: 1
+idouble: 2
ifloat: 2
Function: Real part of "cpow":
ldouble: 2
Function: Real part of "cpow_downward":
-double: 4
+double: 5
float: 8
-idouble: 4
+idouble: 5
ifloat: 8
Function: Imaginary part of "cpow_downward":
ifloat: 2
Function: Real part of "cpow_towardzero":
-double: 4
+double: 5
float: 8
-idouble: 4
+idouble: 5
ifloat: 8
Function: Imaginary part of "cpow_towardzero":
ifloat: 1
Function: Real part of "csin_downward":
-double: 2
+double: 3
float: 3
-idouble: 2
+idouble: 3
ifloat: 3
Function: Imaginary part of "csin_downward":
ifloat: 2
Function: Real part of "csin_towardzero":
-double: 2
+double: 3
float: 3
-idouble: 2
+idouble: 3
ifloat: 3
Function: Imaginary part of "csin_towardzero":
ifloat: 2
Function: Imaginary part of "csinh_downward":
-double: 2
+double: 3
float: 3
-idouble: 2
+idouble: 3
ifloat: 3
Function: Real part of "csinh_towardzero":
ifloat: 2
Function: Imaginary part of "csinh_towardzero":
-double: 2
+double: 3
float: 3
-idouble: 2
+idouble: 3
ifloat: 3
Function: Real part of "csinh_upward":
ldouble: 6
Function: "exp10_downward":
-double: 2
+double: 3
float: 1
-idouble: 2
+idouble: 3
ifloat: 1
Function: "exp10_towardzero":
-double: 2
+double: 3
float: 1
-idouble: 2
+idouble: 3
ifloat: 1
Function: "exp10_upward":
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),
break;
}
default:
- /* This should not happen. */
+ /* Fallback to generic output mechanism. */
return -1;
}
_dl_printf ("\n");
};
#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
{
int i;
- /* Fallback to unknown output mechanism. */
- if (type == AT_HWCAP2)
+ /* Fallback to generic output mechanism. */
+ if (type != AT_HWCAP)
return -1;
_dl_printf ("AT_HWCAP: ");
+++ /dev/null
-/* Copyright (C) 1991-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 <sysdep.h>
-
-
-PSEUDO (__getegid, getxgid, 0)
- MOVE (r1, r0)
- ret
-PSEUDO_END (__getegid)
-
-weak_alias (__getegid, getegid)
+++ /dev/null
-/* Copyright (C) 1991-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 <sysdep.h>
-
-
-PSEUDO (__geteuid, getxuid, 0)
- MOVE (r1, r0)
- ret
-PSEUDO_END (__geteuid)
-
-weak_alias (__geteuid, geteuid)
+++ /dev/null
-/* Copyright (C) 1991-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 <sysdep.h>
-
-
-PSEUDO (__getppid, getxpid, 0)
- MOVE (r1, r0)
- ret
-PSEUDO_END (__getppid)
-
-weak_alias (__getppid, getppid)
ifeq ($(subdir),socket)
sysdep_headers += net/if_ppp.h net/ppp-comp.h \
net/ppp_defs.h net/if_arp.h net/route.h net/ethernet.h \
- net/if_slip.h net/if_packet.h net/if_shaper.h
+ net/if_slip.h net/if_packet.h net/if_shaper.h \
+ bits/socket-constants.h
sysdep_routines += cmsg_nxthdr
CFLAGS-recvmmsg.c = -fexceptions -fasynchronous-unwind-tables
CFLAGS-sendmmsg.c = -fexceptions -fasynchronous-unwind-tables
-endif
+
+tests-special += $(objpfx)tst-socket-consts.out
+$(objpfx)tst-socket-consts.out: ../sysdeps/unix/sysv/linux/tst-socket-consts.py
+ PYTHONPATH=../scripts \
+ $(PYTHON) ../sysdeps/unix/sysv/linux/tst-socket-consts.py \
+ --cc="$(CC) $(patsubst -DMODULE_NAME=%, \
+ -DMODULE_NAME=testsuite, \
+ $(CPPFLAGS)) -D_ISOMAC" \
+ < /dev/null > $@ 2>&1; $(evaluate-test)
+endif # $(subdir) == socket
ifeq ($(subdir),sunrpc)
sysdep_headers += nfs/nfs.h
--- /dev/null
+/* Socket constants which vary among Linux architectures. Version for alpha.
+ 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 _SYS_SOCKET_H
+# error "Never include <bits/socket-constants.h> directly; use <sys/socket.h> instead."
+#endif
+
+#define SOL_SOCKET 65535
+#define SO_ACCEPTCONN 4116
+#define SO_BROADCAST 32
+#define SO_DONTROUTE 16
+#define SO_ERROR 4103
+#define SO_KEEPALIVE 8
+#define SO_LINGER 128
+#define SO_OOBINLINE 256
+#define SO_RCVBUF 4098
+#define SO_RCVLOWAT 4112
+#define SO_RCVTIMEO 4114
+#define SO_REUSEADDR 4
+#define SO_SNDBUF 4097
+#define SO_SNDLOWAT 4113
+#define SO_SNDTIMEO 4115
+#define SO_TYPE 4104
--- /dev/null
+/* Copyright (C) 1991-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 <sysdep.h>
+
+
+PSEUDO (__getegid, getxgid, 0)
+ MOVE (r1, r0)
+ ret
+PSEUDO_END (__getegid)
+
+weak_alias (__getegid, getegid)
--- /dev/null
+/* Copyright (C) 1991-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 <sysdep.h>
+
+
+PSEUDO (__geteuid, getxuid, 0)
+ MOVE (r1, r0)
+ ret
+PSEUDO_END (__geteuid)
+
+weak_alias (__geteuid, geteuid)
--- /dev/null
+/* Copyright (C) 1991-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 <sysdep.h>
+
+
+PSEUDO (__getppid, getxpid, 0)
+ MOVE (r1, r0)
+ ret
+PSEUDO_END (__getppid)
+
+weak_alias (__getppid, getppid)
#undef __ASSUME_STATFS64
#define __ASSUME_STATFS64 0
-/* Alpha defines SysV ipc shmat syscall with a different name. */
-#define __NR_shmat __NR_osf_shmat
+/* Alpha used to define SysV ipc shmat syscall with a different name. */
+#ifndef __NR_shmat
+# define __NR_shmat __NR_osf_shmat
+#endif
#define __ASSUME_RECV_SYSCALL 1
#define __ASSUME_SEND_SYSCALL 1
/* Support for copy_file_range, statx was added in kernel 4.13. */
#if __LINUX_KERNEL_VERSION < 0x040D00
# undef __ASSUME_MLOCK2
-# undef __ASSUME_COPY_FILE_RANGE
# undef __ASSUME_STATX
#endif
* Some syscalls no Linux program should know about:
*/
#define __NR_osf_sigprocmask 48
-#define __NR_osf_shmat 209
+#ifndef __NR_osf_shmat
+# define __NR_osf_shmat 209
+#endif
#define __NR_osf_getsysinfo 256
#define __NR_osf_setsysinfo 257
break;
}
default:
- /* This should not happen. */
+ /* Fallback to generic output mechanism. */
return -1;
}
_dl_printf ("\n");
present in 32-bit kernels from 4.4 and 4.5 respectively. */
#if __LINUX_KERNEL_VERSION < 0x040700
# undef __ASSUME_MLOCK2
-# undef __ASSUME_COPY_FILE_RANGE
#endif
#undef __ASSUME_CLONE_DEFAULT
--- /dev/null
+/* Socket constants which vary among Linux architectures.
+ 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 _SYS_SOCKET_H
+# error "Never include <bits/socket-constants.h> directly; use <sys/socket.h> instead."
+#endif
+
+#define SOL_SOCKET 1
+#define SO_ACCEPTCONN 30
+#define SO_BROADCAST 6
+#define SO_DONTROUTE 5
+#define SO_ERROR 4
+#define SO_KEEPALIVE 9
+#define SO_LINGER 13
+#define SO_OOBINLINE 10
+#define SO_RCVBUF 8
+#define SO_RCVLOWAT 18
+#define SO_RCVTIMEO 20
+#define SO_REUSEADDR 2
+#define SO_SNDBUF 7
+#define SO_SNDLOWAT 19
+#define SO_SNDTIMEO 21
+#define SO_TYPE 3
};
#endif
-/* Ugly workaround for unclean kernel headers. */
-#ifndef __USE_MISC
-# ifndef FIOGETOWN
-# define __SYS_SOCKET_H_undef_FIOGETOWN
-# endif
-# ifndef FIOSETOWN
-# define __SYS_SOCKET_H_undef_FIOSETOWN
-# endif
-# ifndef SIOCATMARK
-# define __SYS_SOCKET_H_undef_SIOCATMARK
-# endif
-# ifndef SIOCGPGRP
-# define __SYS_SOCKET_H_undef_SIOCGPGRP
-# endif
-# ifndef SIOCGSTAMP
-# define __SYS_SOCKET_H_undef_SIOCGSTAMP
-# endif
-# ifndef SIOCGSTAMPNS
-# define __SYS_SOCKET_H_undef_SIOCGSTAMPNS
-# endif
-# ifndef SIOCSPGRP
-# define __SYS_SOCKET_H_undef_SIOCSPGRP
-# endif
-#endif
-#ifndef IOCSIZE_MASK
-# define __SYS_SOCKET_H_undef_IOCSIZE_MASK
-#endif
-#ifndef IOCSIZE_SHIFT
-# define __SYS_SOCKET_H_undef_IOCSIZE_SHIFT
-#endif
-#ifndef IOC_IN
-# define __SYS_SOCKET_H_undef_IOC_IN
-#endif
-#ifndef IOC_INOUT
-# define __SYS_SOCKET_H_undef_IOC_INOUT
-#endif
-#ifndef IOC_OUT
-# define __SYS_SOCKET_H_undef_IOC_OUT
-#endif
-
-/* Get socket manipulation related informations from kernel headers. */
-#include <asm/socket.h>
-
-#ifndef __USE_MISC
-# ifdef __SYS_SOCKET_H_undef_FIOGETOWN
-# undef __SYS_SOCKET_H_undef_FIOGETOWN
-# undef FIOGETOWN
-# endif
-# ifdef __SYS_SOCKET_H_undef_FIOSETOWN
-# undef __SYS_SOCKET_H_undef_FIOSETOWN
-# undef FIOSETOWN
-# endif
-# ifdef __SYS_SOCKET_H_undef_SIOCATMARK
-# undef __SYS_SOCKET_H_undef_SIOCATMARK
-# undef SIOCATMARK
-# endif
-# ifdef __SYS_SOCKET_H_undef_SIOCGPGRP
-# undef __SYS_SOCKET_H_undef_SIOCGPGRP
-# undef SIOCGPGRP
-# endif
-# ifdef __SYS_SOCKET_H_undef_SIOCGSTAMP
-# undef __SYS_SOCKET_H_undef_SIOCGSTAMP
-# undef SIOCGSTAMP
-# endif
-# ifdef __SYS_SOCKET_H_undef_SIOCGSTAMPNS
-# undef __SYS_SOCKET_H_undef_SIOCGSTAMPNS
-# undef SIOCGSTAMPNS
-# endif
-# ifdef __SYS_SOCKET_H_undef_SIOCSPGRP
-# undef __SYS_SOCKET_H_undef_SIOCSPGRP
-# undef SIOCSPGRP
-# endif
-#endif
-#ifdef __SYS_SOCKET_H_undef_IOCSIZE_MASK
-# undef __SYS_SOCKET_H_undef_IOCSIZE_MASK
-# undef IOCSIZE_MASK
-#endif
-#ifdef __SYS_SOCKET_H_undef_IOCSIZE_SHIFT
-# undef __SYS_SOCKET_H_undef_IOCSIZE_SHIFT
-# undef IOCSIZE_SHIFT
-#endif
-#ifdef __SYS_SOCKET_H_undef_IOC_IN
-# undef __SYS_SOCKET_H_undef_IOC_IN
-# undef IOC_IN
-#endif
-#ifdef __SYS_SOCKET_H_undef_IOC_INOUT
-# undef __SYS_SOCKET_H_undef_IOC_INOUT
-# undef IOC_INOUT
-#endif
-#ifdef __SYS_SOCKET_H_undef_IOC_OUT
-# undef __SYS_SOCKET_H_undef_IOC_OUT
-# undef IOC_OUT
+#ifdef __USE_MISC
+# include <bits/types/time_t.h>
+# include <asm/socket.h>
+#else
+# define SO_DEBUG 1
+# include <bits/socket-constants.h>
#endif
/* Structure used to manipulate the SO_LINGER option. */
#include <sysdep-cancel.h>
#include <unistd.h>
-/* Include the fallback implementation. */
-#ifndef __ASSUME_COPY_FILE_RANGE
-#define COPY_FILE_RANGE_DECL static
-#define COPY_FILE_RANGE copy_file_range_compat
-#include <io/copy_file_range-compat.c>
-#endif
-
ssize_t
copy_file_range (int infd, __off64_t *pinoff,
int outfd, __off64_t *poutoff,
size_t length, unsigned int flags)
{
#ifdef __NR_copy_file_range
- ssize_t ret = SYSCALL_CANCEL (copy_file_range, infd, pinoff, outfd, poutoff,
- length, flags);
-# ifndef __ASSUME_COPY_FILE_RANGE
- if (ret == -1 && errno == ENOSYS)
- ret = copy_file_range_compat (infd, pinoff, outfd, poutoff, length, flags);
-# endif
- return ret;
-#else /* !__NR_copy_file_range */
- return copy_file_range_compat (infd, pinoff, outfd, poutoff, length, flags);
+ return SYSCALL_CANCEL (copy_file_range, infd, pinoff, outfd, poutoff,
+ length, flags);
+#else
+ __set_errno (ENOSYS);
+ return -1;
#endif
}
--- /dev/null
+/* Socket constants which vary among Linux architectures. Version for hppa.
+ 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 _SYS_SOCKET_H
+# error "Never include <bits/socket-constants.h> directly; use <sys/socket.h> instead."
+#endif
+
+#define SOL_SOCKET 65535
+#define SO_ACCEPTCONN 16412
+#define SO_BROADCAST 32
+#define SO_DONTROUTE 16
+#define SO_ERROR 4103
+#define SO_KEEPALIVE 8
+#define SO_LINGER 128
+#define SO_OOBINLINE 256
+#define SO_RCVBUF 4098
+#define SO_RCVLOWAT 4100
+#define SO_RCVTIMEO 4102
+#define SO_REUSEADDR 4
+#define SO_SNDBUF 4097
+#define SO_SNDLOWAT 4099
+#define SO_SNDTIMEO 4101
+#define SO_TYPE 4104
in the kernel sources. */
int i;
- /* Fallback to unknown output mechanism. */
- if (type == AT_HWCAP2)
+ /* Fallback to generic output mechanism. */
+ if (type != AT_HWCAP)
return -1;
_dl_printf ("AT_HWCAP: ");
# define __ASSUME_MLOCK2 1
#endif
-#if __LINUX_KERNEL_VERSION >= 0x040500
-# define __ASSUME_COPY_FILE_RANGE 1
-#endif
-
/* Support for statx was added in kernel 4.11. */
#if __LINUX_KERNEL_VERSION >= 0x040B00
# define __ASSUME_STATX 1
# undef __ASSUME_MLOCK2
#endif
-/* Support for the copy_file_range syscall was added in 4.10. */
-#if __LINUX_KERNEL_VERSION < 0x040A00
-# undef __ASSUME_COPY_FILE_RANGE
-#endif
-
/* Support for statx was added in kernel 4.12. */
#if __LINUX_KERNEL_VERSION < 0X040C00
# undef __ASSUME_STATX
sysdep_routines += dl-vdso
endif
-
-# Supporting non-executable stacks on MIPS requires changes to both
-# the Linux kernel and glibc. See
-# <https://sourceware.org/ml/libc-alpha/2016-01/msg00567.html> and
-# <https://sourceware.org/ml/libc-alpha/2016-01/msg00719.html>.
+# If the compiler doesn't use GNU.stack note,
+# this test is expected to fail.
+ifneq ($(mips-has-gnustack),yes)
test-xfail-check-execstack = yes
endif
+endif
ifeq ($(subdir),stdlib)
gen-as-const-headers += ucontext_i.sym
endif
+
+ifeq ($(mips-force-execstack),yes)
+CFLAGS-.o += -Wa,-execstack
+CFLAGS-.os += -Wa,-execstack
+CFLAGS-.op += -Wa,-execstack
+CFLAGS-.oS += -Wa,-execstack
+
+ASFLAGS-.o += -Wa,-execstack
+ASFLAGS-.os += -Wa,-execstack
+ASFLAGS-.op += -Wa,-execstack
+ASFLAGS-.oS += -Wa,-execstack
+endif
--- /dev/null
+/* Socket constants which vary among Linux architectures. Version for MIPS.
+ 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 _SYS_SOCKET_H
+# error "Never include <bits/socket-constants.h> directly; use <sys/socket.h> instead."
+#endif
+
+#define SOL_SOCKET 65535
+#define SO_ACCEPTCONN 4105
+#define SO_BROADCAST 32
+#define SO_DONTROUTE 16
+#define SO_ERROR 4103
+#define SO_KEEPALIVE 8
+#define SO_LINGER 128
+#define SO_OOBINLINE 256
+#define SO_RCVBUF 4098
+#define SO_RCVLOWAT 4100
+#define SO_RCVTIMEO 4102
+#define SO_REUSEADDR 4
+#define SO_SNDBUF 4097
+#define SO_SNDLOWAT 4099
+#define SO_SNDTIMEO 4101
+#define SO_TYPE 4104
arch_minimum_kernel=4.5.0
fi
fi
+
+# Check if we are supposed to run on kernels older than 4.8.0. If so,
+# force executable stack to avoid potential runtime problems with fpu
+# emulation.
+# NOTE: The check below assumes that in absence of user-provided minumum_kernel
+# we will default to arch_minimum_kernel which is currently less than 4.8.0 for
+# all known configurations. If this changes, the check must be updated.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler must use executable stack" >&5
+$as_echo_n "checking whether the compiler must use executable stack... " >&6; }
+if ${libc_cv_mips_force_execstack+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ libc_cv_mips_force_execstack=no
+ if test $libc_mips_float = hard; then
+ if test -n "$minimum_kernel"; then
+
+ min_version=$((`echo "$minimum_kernel.0.0.0" | sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\).*/\1 \* 65536 + \2 \* 256 + \3/'`))
+
+ if test $min_version -lt 264192; then
+ libc_cv_mips_force_execstack=yes
+ fi
+ else
+ libc_cv_mips_force_execstack=yes
+ fi
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_mips_force_execstack" >&5
+$as_echo "$libc_cv_mips_force_execstack" >&6; }
+
+libc_mips_has_gnustack=$libc_cv_as_noexecstack
+
+if test $libc_cv_mips_force_execstack = yes; then
+ libc_mips_has_gnustack=no
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: forcing executable stack for pre-4.8.0 Linux kernels" >&5
+$as_echo "$as_me: WARNING: forcing executable stack for pre-4.8.0 Linux kernels" >&2;}
+fi
+
+config_vars="$config_vars
+mips-force-execstack = ${libc_cv_mips_force_execstack}"
+config_vars="$config_vars
+mips-has-gnustack = ${libc_mips_has_gnustack}"
arch_minimum_kernel=4.5.0
fi
fi
+
+# Check if we are supposed to run on kernels older than 4.8.0. If so,
+# force executable stack to avoid potential runtime problems with fpu
+# emulation.
+# NOTE: The check below assumes that in absence of user-provided minumum_kernel
+# we will default to arch_minimum_kernel which is currently less than 4.8.0 for
+# all known configurations. If this changes, the check must be updated.
+AC_CACHE_CHECK([whether the compiler must use executable stack],
+ libc_cv_mips_force_execstack, [dnl
+libc_cv_mips_force_execstack=no
+ if test $libc_mips_float = hard; then
+ if test -n "$minimum_kernel"; then
+ changequote(,)
+ min_version=$((`echo "$minimum_kernel.0.0.0" | sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\).*/\1 \* 65536 + \2 \* 256 + \3/'`))
+ changequote([,])
+ if test $min_version -lt 264192; then
+ libc_cv_mips_force_execstack=yes
+ fi
+ else
+ libc_cv_mips_force_execstack=yes
+ fi
+ fi])
+
+libc_mips_has_gnustack=$libc_cv_as_noexecstack
+
+if test $libc_cv_mips_force_execstack = yes; then
+ libc_mips_has_gnustack=no
+ AC_MSG_WARN([forcing executable stack for pre-4.8.0 Linux kernels])
+fi
+
+LIBC_CONFIG_VAR([mips-force-execstack],[${libc_cv_mips_force_execstack}])
+LIBC_CONFIG_VAR([mips-has-gnustack],[${libc_mips_has_gnustack}])
--- /dev/null
+/* mips64n32 uses __NR_mmap for mmap64 while still having sizeof (off_t)
+ smaller than sizeof (off64_t). So it allows mapping large offsets
+ using mmap64 than 32-bit archs which uses __NR_mmap2. */
+
+static inline uint64_t
+mmap64_maximum_offset (long int page_shift)
+{
+#if _MIPS_SIM == _ABIN32 || _MIPS_SIM == _ABI64
+ return UINT64_MAX;
+#else
+ return (UINT64_C(1) << (page_shift + (8 * sizeof (off_t)))) - 1;
+#endif
+}
#include <sysdep.h>
#include <mmap_internal.h>
+#ifdef __NR_mmap2
/* To avoid silent truncation of offset when using mmap2, do not accept
offset larger than 1 << (page_shift + off_t bits). For archictures with
32 bits off_t and page size of 4096 it would be 1^44. */
-#define MMAP_OFF_HIGH_MASK \
+# define MMAP_OFF_HIGH_MASK \
((-(MMAP2_PAGE_UNIT << 1) << (8 * sizeof (off_t) - 1)))
+#else
+/* Some ABIs might use __NR_mmap while having sizeof (off_t) smaller than
+ sizeof (off64_t) (currently only MIPS64n32). For this case just set
+ zero the higher bits so mmap with large offset does not fail. */
+# define MMAP_OFF_HIGH_MASK 0x0
+#endif
#define MMAP_OFF_MASK (MMAP_OFF_HIGH_MASK | MMAP_OFF_LOW_MASK)
--- /dev/null
+/* Socket constants which vary among Linux architectures. Version for POWER.
+ 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 _SYS_SOCKET_H
+# error "Never include <bits/socket-constants.h> directly; use <sys/socket.h> instead."
+#endif
+
+#define SOL_SOCKET 1
+#define SO_ACCEPTCONN 30
+#define SO_BROADCAST 6
+#define SO_DONTROUTE 5
+#define SO_ERROR 4
+#define SO_KEEPALIVE 9
+#define SO_LINGER 13
+#define SO_OOBINLINE 10
+#define SO_RCVBUF 8
+#define SO_RCVLOWAT 16
+#define SO_RCVTIMEO 18
+#define SO_REUSEADDR 2
+#define SO_SNDBUF 7
+#define SO_SNDLOWAT 17
+#define SO_SNDTIMEO 19
+#define SO_TYPE 3
#include <sys/asm.h>
#include <sysdep.h>
#define __ASSEMBLY__
-#include <linux/sched.h>
#include <asm/signal.h>
+#define CLONE_VM 0x00000100 /* Set if VM shared between processes. */
+#define CLONE_VFORK 0x00004000 /* Set if the parent wants the child to
+ wake it up on mm_release. */
+
.text
LEAF (__libc_vfork)
in the kernel sources. */
int i;
- /* Fallback to unknown output mechanism. */
- if (type == AT_HWCAP2)
+ /* Fallback to generic output mechanism. */
+ if (type != AT_HWCAP)
return -1;
_dl_printf ("AT_HWCAP: ");
# undef __ASSUME_RENAMEAT2
# undef __ASSUME_EXECVEAT
# undef __ASSUME_MLOCK2
-# undef __ASSUME_COPY_FILE_RANGE
#endif
/* sh does not support the statx system call. */
--- /dev/null
+/* Socket constants which vary among Linux architectures. Version for SPARC.
+ 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 _SYS_SOCKET_H
+# error "Never include <bits/socket-constants.h> directly; use <sys/socket.h> instead."
+#endif
+
+#define SOL_SOCKET 65535
+#define SO_ACCEPTCONN 32768
+#define SO_BROADCAST 32
+#define SO_DONTROUTE 16
+#define SO_ERROR 4103
+#define SO_KEEPALIVE 8
+#define SO_LINGER 128
+#define SO_OOBINLINE 256
+#define SO_RCVBUF 4098
+#define SO_RCVLOWAT 2048
+#define SO_RCVTIMEO 8192
+#define SO_REUSEADDR 4
+#define SO_SNDBUF 4097
+#define SO_SNDLOWAT 4096
+#define SO_SNDTIMEO 16384
+#define SO_TYPE 4104
fails |= test_wrp (EINVAL, poll, &pollfd, -1, 0);
/* quotactl returns ENOSYS for kernels not configured with
CONFIG_QUOTA, and may return EPERM if called within certain types
- of containers. */
- fails |= test_wrp2 (LIST (ENODEV, ENOSYS, EPERM),
+ of containers. Linux 5.4 added additional argument validation
+ and can return EINVAL. */
+ fails |= test_wrp2 (LIST (ENODEV, ENOSYS, EPERM, EINVAL),
quotactl, Q_GETINFO, NULL, -1, (caddr_t) &dqblk);
fails |= test_wrp (EINVAL, sched_getparam, -1, &sch_param);
fails |= test_wrp (EINVAL, sched_getscheduler, -1);
--- /dev/null
+#!/usr/bin/python3
+# Test that glibc's sys/socket.h SO_* constants match the kernel's.
+# Copyright (C) 2018-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/>.
+
+import argparse
+import sys
+
+import glibcextract
+
+def main():
+ """The main entry point."""
+ parser = argparse.ArgumentParser(
+ description="Test that glibc's sys/socket.h constants "
+ "match the kernel's.")
+ parser.add_argument('--cc', metavar='CC',
+ help='C compiler (including options) to use')
+ args = parser.parse_args()
+
+ def check(define):
+ return glibcextract.compare_macro_consts(
+ source_1=define + '#include <sys/socket.h>\n',
+ # Some constants in <asm/socket.h> may depend on the size
+ # of pid_t or time_t.
+ source_2='#include <sys/types.h>\n'
+ '#include <asm/socket.h>\n',
+ cc=args.cc,
+ # We cannot compare all macros because some macros cannot
+ # be expanded as constants, and glibcextract currently is
+ # not able to isolate errors.
+ macro_re='SOL?_.*',
+ # <sys/socket.h> and <asm/socket.h> are not a good match.
+ # Most socket-related constants are not defined in any
+ # UAPI header. Check only the intersection of the macros
+ # in both headers. Regular tests ensure that expected
+ # macros for _GNU_SOURCE are present, and the conformance
+ # tests cover most of the other modes.
+ allow_extra_1=True,
+ allow_extra_2=True)
+ # _GNU_SOURCE is defined by include/libc-symbols.h, which is
+ # included by the --cc command. Defining _ISOMAC does not prevent
+ # that.
+ status = max(
+ check(''),
+ check('#undef _GNU_SOURCE\n'),
+ check('#undef _GNU_SOURCE\n'
+ '#define _POSIX_SOURCE 1\n'))
+ sys.exit(status)
+
+if __name__ == '__main__':
+ main()
environment variable, LD_PREFER_MAP_32BIT_EXEC. */
#define EXTRA_LD_ENVVARS \
case 21: \
- if (memcmp (envline, "PREFER_MAP_32BIT_EXEC", 21) == 0) \
+ if (!__libc_enable_secure \
+ && memcmp (envline, "PREFER_MAP_32BIT_EXEC", 21) == 0) \
GLRO(dl_x86_cpu_features).feature[index_arch_Prefer_MAP_32BIT_EXEC] \
|= bit_arch_Prefer_MAP_32BIT_EXEC; \
break;
sysdep-dl-routines += dl-cet
tests += tst-cet-legacy-1 tst-cet-legacy-1a tst-cet-legacy-2 \
- tst-cet-legacy-2a tst-cet-legacy-3 tst-cet-legacy-4
+ tst-cet-legacy-2a tst-cet-legacy-3 tst-cet-legacy-4 \
+ tst-cet-legacy-5a tst-cet-legacy-6a
tst-cet-legacy-1a-ARGS = -- $(host-test-program-cmd)
ifneq (no,$(have-tunables))
-tests += tst-cet-legacy-4a tst-cet-legacy-4b tst-cet-legacy-4c
+tests += tst-cet-legacy-4a tst-cet-legacy-4b tst-cet-legacy-4c \
+ tst-cet-legacy-5b tst-cet-legacy-6b
endif
modules-names += tst-cet-legacy-mod-1 tst-cet-legacy-mod-2 \
- tst-cet-legacy-mod-4
+ tst-cet-legacy-mod-4 tst-cet-legacy-mod-5a \
+ tst-cet-legacy-mod-5b tst-cet-legacy-mod-5c \
+ tst-cet-legacy-mod-6a tst-cet-legacy-mod-6b \
+ tst-cet-legacy-mod-6c
CFLAGS-tst-cet-legacy-2.c += -fcf-protection=branch
CFLAGS-tst-cet-legacy-2a.c += -fcf-protection
CFLAGS-tst-cet-legacy-4a.c += -fcf-protection
CFLAGS-tst-cet-legacy-4b.c += -fcf-protection
CFLAGS-tst-cet-legacy-mod-4.c += -fcf-protection=none
+CFLAGS-tst-cet-legacy-5a.c += -fcf-protection
+CFLAGS-tst-cet-legacy-5b.c += -fcf-protection
+CFLAGS-tst-cet-legacy-mod-5a.c += -fcf-protection=none
+CFLAGS-tst-cet-legacy-mod-5b.c += -fcf-protection
+CFLAGS-tst-cet-legacy-mod-5c.c += -fcf-protection
+CFLAGS-tst-cet-legacy-6a.c += -fcf-protection
+CFLAGS-tst-cet-legacy-6b.c += -fcf-protection
+CFLAGS-tst-cet-legacy-mod-6a.c += -fcf-protection=none
+CFLAGS-tst-cet-legacy-mod-6b.c += -fcf-protection
+CFLAGS-tst-cet-legacy-mod-6c.c += -fcf-protection
$(objpfx)tst-cet-legacy-1: $(objpfx)tst-cet-legacy-mod-1.so \
$(objpfx)tst-cet-legacy-mod-2.so
$(objpfx)tst-cet-legacy-2a.out: $(objpfx)tst-cet-legacy-mod-1.so
$(objpfx)tst-cet-legacy-4: $(libdl)
$(objpfx)tst-cet-legacy-4.out: $(objpfx)tst-cet-legacy-mod-4.so
+$(objpfx)tst-cet-legacy-5a: $(libdl)
+$(objpfx)tst-cet-legacy-5a.out: $(objpfx)tst-cet-legacy-mod-5a.so \
+ $(objpfx)tst-cet-legacy-mod-5b.so
+$(objpfx)tst-cet-legacy-mod-5a.so: $(objpfx)tst-cet-legacy-mod-5c.so
+$(objpfx)tst-cet-legacy-mod-5b.so: $(objpfx)tst-cet-legacy-mod-5c.so
+$(objpfx)tst-cet-legacy-6a: $(libdl)
+$(objpfx)tst-cet-legacy-6a.out: $(objpfx)tst-cet-legacy-mod-6a.so \
+ $(objpfx)tst-cet-legacy-mod-6b.so
+$(objpfx)tst-cet-legacy-mod-6a.so: $(objpfx)tst-cet-legacy-mod-6c.so
+$(objpfx)tst-cet-legacy-mod-6b.so: $(objpfx)tst-cet-legacy-mod-6c.so
+LDFLAGS-tst-cet-legacy-mod-6c.so = -Wl,--enable-new-dtags,-z,nodelete
ifneq (no,$(have-tunables))
$(objpfx)tst-cet-legacy-4a: $(libdl)
$(objpfx)tst-cet-legacy-4a.out: $(objpfx)tst-cet-legacy-mod-4.so
$(objpfx)tst-cet-legacy-4c: $(libdl)
$(objpfx)tst-cet-legacy-4c.out: $(objpfx)tst-cet-legacy-mod-4.so
tst-cet-legacy-4c-ENV = GLIBC_TUNABLES=glibc.cpu.x86_shstk=off
+$(objpfx)tst-cet-legacy-5b: $(libdl)
+$(objpfx)tst-cet-legacy-5b.out: $(objpfx)tst-cet-legacy-mod-5a.so \
+ $(objpfx)tst-cet-legacy-mod-5b.so
+tst-cet-legacy-5b-ENV = GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK
+$(objpfx)tst-cet-legacy-6b: $(libdl)
+$(objpfx)tst-cet-legacy-6b.out: $(objpfx)tst-cet-legacy-mod-6a.so \
+ $(objpfx)tst-cet-legacy-mod-6b.so
+tst-cet-legacy-6b-ENV = GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK
endif
endif
--- /dev/null
+/* Check compatibility of CET-enabled executable with dlopened legacy
+ shared object.
+ 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 <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+
+static void
+do_test_1 (const char *modname, bool fail)
+{
+ int (*fp) (void);
+ void *h;
+
+ h = dlopen (modname, RTLD_LAZY);
+ if (h == NULL)
+ {
+ if (fail)
+ {
+ const char *err = dlerror ();
+ if (strstr (err, "shadow stack isn't enabled") == NULL)
+ {
+ printf ("incorrect dlopen '%s' error: %s\n", modname,
+ dlerror ());
+ exit (1);
+ }
+
+ return;
+ }
+
+ printf ("cannot open '%s': %s\n", modname, dlerror ());
+ exit (1);
+ }
+
+ fp = dlsym (h, "test");
+ if (fp == NULL)
+ {
+ printf ("cannot get symbol 'test': %s\n", dlerror ());
+ exit (1);
+ }
+
+ if (fp () != 0)
+ {
+ puts ("test () != 0");
+ exit (1);
+ }
+
+ dlclose (h);
+}
+
+static int
+do_test (void)
+{
+ do_test_1 ("tst-cet-legacy-mod-5a.so", true);
+ do_test_1 ("tst-cet-legacy-mod-5b.so", false);
+ return 0;
+}
+
+#include <support/test-driver.c>
--- /dev/null
+#include "tst-cet-legacy-5.c"
--- /dev/null
+#include "tst-cet-legacy-5.c"
--- /dev/null
+/* Check compatibility of CET-enabled executable with dlopened legacy
+ shared object.
+ 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 <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+
+static void
+do_test_1 (const char *modname, bool fail)
+{
+ int (*fp) (void);
+ void *h;
+
+ h = dlopen (modname, RTLD_LAZY);
+ if (h == NULL)
+ {
+ if (fail)
+ {
+ const char *err = dlerror ();
+ if (strstr (err, "shadow stack isn't enabled") == NULL)
+ {
+ printf ("incorrect dlopen '%s' error: %s\n", modname,
+ dlerror ());
+ exit (1);
+ }
+
+ return;
+ }
+
+ printf ("cannot open '%s': %s\n", modname, dlerror ());
+ exit (1);
+ }
+
+ fp = dlsym (h, "test");
+ if (fp == NULL)
+ {
+ printf ("cannot get symbol 'test': %s\n", dlerror ());
+ exit (1);
+ }
+
+ if (fp () != 0)
+ {
+ puts ("test () != 0");
+ exit (1);
+ }
+
+ dlclose (h);
+}
+
+static int
+do_test (void)
+{
+ do_test_1 ("tst-cet-legacy-mod-6a.so", true);
+ do_test_1 ("tst-cet-legacy-mod-6b.so", false);
+ return 0;
+}
+
+#include <support/test-driver.c>
--- /dev/null
+#include "tst-cet-legacy-6.c"
--- /dev/null
+#include "tst-cet-legacy-6.c"
--- /dev/null
+/* Check compatibility of CET-enabled executable with dlopened legacy
+ shared object.
+ 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 <error.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+extern void foo (void);
+
+int
+test (void)
+{
+ foo ();
+ return 0;
+}
--- /dev/null
+#include "tst-cet-legacy-mod-5.c"
--- /dev/null
+#include "tst-cet-legacy-mod-5.c"
--- /dev/null
+/* Check compatibility of CET-enabled executable with dlopened legacy
+ shared object.
+ 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 <stdlib.h>
+
+static int called = 0;
+
+static void
+__attribute__ ((constructor))
+init (void)
+{
+ called = 1;
+}
+
+void
+foo (void)
+{
+ if (!called)
+ abort ();
+}
--- /dev/null
+/* Check compatibility of CET-enabled executable with dlopened legacy
+ shared object.
+ 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 <error.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+extern void foo (void);
+
+int
+test (void)
+{
+ foo ();
+ return 0;
+}
--- /dev/null
+#include "tst-cet-legacy-mod-6.c"
--- /dev/null
+#include "tst-cet-legacy-mod-6.c"
--- /dev/null
+/* Check compatibility of CET-enabled executable with dlopened legacy
+ shared object.
+ 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 <stdlib.h>
+
+static int called = 0;
+
+static void
+__attribute__ ((constructor))
+init (void)
+{
+ called = 1;
+}
+
+void
+foo (void)
+{
+ if (!called)
+ abort ();
+}
--- /dev/null
+#include "tst-cet-legacy-mod-6c.c"
.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
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-strncmp tst-size_t-strncpy tst-size_t-strnlen \
+ tst-size_t-memcmp-2
endif
ifeq ($(subdir),wcsmbs)
--- /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>