GIT update of https://sourceware.org/git/glibc.git/release/2.28/master from glibc-2.28
Gbp-Pq: Name git-updates.diff
+2018-11-26 Florian Weimer <fweimer@redhat.com>
+
+ [BZ #23907]
+ * malloc/malloc.c (_int_free): Validate tc_idx before checking for
+ double-frees.
+
+
+2018-11-20 DJ Delorie <dj@redhat.com>
+
+ * malloc/malloc.c (tcache_entry): Add key field.
+ (tcache_put): Set it.
+ (tcache_get): Likewise.
+ (_int_free): Check for double free in tcache.
+ * malloc/tst-tcfree1.c: New.
+ * malloc/tst-tcfree2.c: New.
+ * malloc/Makefile: Run the new tests.
+ * manual/probes.texi: Document memory_tcache_double_free probe.
+
+ * dlfcn/dlerror.c (check_free): Prevent double frees.
+
+2018-11-27 Florian Weimer <fweimer@redhat.com>
+
+ [BZ #23927]
+ CVE-2018-19591
+ * sysdeps/unix/sysv/linux/if_index.c (__if_nametoindex): Avoid
+ descriptor leak in case of ENODEV error.
+
+2018-11-19 Florian Weimer <fweimer@redhat.com>
+
+ support: Print timestamps in timeout handler.
+ * support/support_test_main.c (print_timestamp): New function.
+ (signal_handler): Use it to print the termination time and the
+ time of the last write to standard output.
+
+2018-10-09 Szabolcs Nagy <szabolcs.nagy@arm.com>
+
+ * libio/tst-readline.c (TIMEOUT): Define.
+
+2018-10-22 Joseph Myers <joseph@codesourcery.com>
+
+ * sysdeps/unix/sysv/linux/syscall-names.list: Update kernel
+ version to 4.19.
+
+2018-09-18 Paul Eggert <eggert@cs.ucla.edu>
+
+ Fix tzfile low-memory assertion failure
+ [BZ #21716]
+ * time/tzfile.c (__tzfile_read): Check for memory exhaustion
+ when registering time zone abbreviations.
+
+2018-08-31 Paul Pluzhnikov <ppluzhnikov@google.com>
+
+ [BZ #20271]
+ * include/stdio.h (__libc_fatal): Mention newline in comment.
+ * grp/initgroups.c (internal_getgrouplist): Add missing newline.
+ * nptl/pthread_cond_wait.c (__pthread_cond_wait_common): Likewise.
+ * nscd/initgrcache.c (addinitgroupsX): Likewise.
+ * nss/nsswitch.c (__nss_next2): Likewise.
+ * sysdeps/aarch64/dl-irel.h (elf_irela): Likewise.
+ * sysdeps/arm/dl-irel.h (elf_irel): Likewise.
+ * sysdeps/generic/unwind-dw2.c (execute_cfa_program): Likewise.
+ * sysdeps/i386/dl-irel.h (elf_irel): Likewise.
+ * sysdeps/powerpc/powerpc32/dl-irel.h (elf_irel): Likewise.
+ * sysdeps/powerpc/powerpc64/dl-irel.h (elf_irel): Likewise.
+ * sysdeps/s390/dl-irel.h (elf_irel): Likewise.
+ * sysdeps/sparc/sparc32/dl-irel.h (elf_irel): Likewise.
+ * sysdeps/sparc/sparc64/dl-irel.h (elf_irel): Likewise.
+ * sysdeps/x86_64/dl-irel.h (elf_irel): Likewise.
+ * sysdeps/nptl/futex-internal.h (futex_wake): Likewise.
+ * sysdeps/unix/sysv/linux/netlink_assert_response.c
+ (__netlink_assert_response): Likewise.
+
+2018-08-28 Florian Weimer <fweimer@redhat.com>
+
+ [BZ #23520]
+ nscd: Fix use-after-free in addgetnetgrentX and its callers.
+ * nscd/netgroupcache.c
+ (addgetnetgrentX): Add tofreep parameter. Do not free
+ heap-allocated buffer.
+ (addinnetgrX): Free buffer allocated bt addgetnetgrentX.
+ (addgetnetgrentX_ignore): New function.
+ (addgetnetgrent): Call it.
+ (readdgetnetgrent): Likewise.
+
+2018-08-16 DJ Delorie <dj@delorie.com>
+
+ * malloc/malloc.c (_int_free): Check for corrupt prev_size vs size.
+ (malloc_consolidate): Likewise.
+
+2018-08-16 Pochang Chen <johnchen902@gmail.com>
+
+ * malloc/malloc.c (_int_malloc.c): Verify size of top chunk.
+
+2018-08-13 Joseph Myers <joseph@codesourcery.com>
+
+ * sysdeps/unix/sysv/linux/syscall-names.list: Update kernel
+ version to 4.18.
+ (io_pgetevents): New syscall.
+ (rseq): Likewise.
+
+2018-11-08 Alexandra Hájková <ahajkova@redhat.com>
+
+ [BZ #17630]
+ * resolv/tst-resolv-network.c: Add test for getnetbyname.
+
+2018-11-08 H.J. Lu <hongjiu.lu@intel.com>
+
+ [BZ #23509]
+ * sysdeps/x86/dl-prop.h (_dl_process_cet_property_note): Skip
+ note parsing if a NT_GNU_PROPERTY_TYPE_0 note has been processed.
+ Update the l_cet field when processing NT_GNU_PROPERTY_TYPE_0 note.
+ Check multiple NT_GNU_PROPERTY_TYPE_0 notes.
+ * sysdeps/x86/link_map.h (l_cet): Expand to 3 bits, Add
+ lc_unknown.
+
+2018-11-05 Andreas Schwab <schwab@suse.de>
+
+ [BZ #22927]
+ * resolv/gai_misc.c (__gai_enqueue_request): Don't crash if
+ creating the first helper thread failed.
+
+2018-10-23 Adhemerval Zanella <adhemerval.zanella@linaro.org>
+
+ [BZ #23709]
+ * sysdeps/x86/cpu-features.c (init_cpu_features): Set TSX bits
+ independently of other flags.
+
+2018-10-30 Florian Weimer <fweimer@redhat.com>
+
+ * stdlib/tst-strtod-overflow.c (do_test): Switch to
+ support_blob_repeat.
+
+2018-10-30 Florian Weimer <fweimer@redhat.com>
+
+ * support/blob_repeat.c (allocate_big): Call mkstemp directly.
+
+2018-10-30 Florian Weimer <fweimer@redhat.com>
+
+ * stdlib/test-bz22786.c (do_test): Additional free calls to avoid
+ memory leaks.
+
+2018-10-30 Florian Weimer <fweimer@redhat.com>
+
+ Avoid spurious test failures in stdlib/test-bz22786.
+ * support/Makefile (libsupport-routines): Add blob_repeat.
+ (tests): Add tst-support_blob_repeat.
+ * support/blob_repeat.h: New file.
+ * support/blob_repeat.c: Likewise.
+ * support/tst-support_blob_repeat.c: Likewise.
+ * stdlib/test-bz22786.c (do_test): Replace malloc and memset with
+ support_blob_repeat_allocate.
+
+2018-08-30 Stefan Liebler <stli@linux.ibm.com>
+
+ * stdlib/test-bz22786.c (do_test): Return EXIT_UNSUPPORTED
+ if malloc fails.
+
+2018-08-24 Paul Pluzhnikov <ppluzhnikov@google.com>
+
+ [BZ #23400]
+ * stdlib/test-bz22786.c (do_test): Fix undefined behavior, don't
+ create temporary files in source tree.
+
+2018-10-26 Szabolcs Nagy <szabolcs.nagy@arm.com>
+
+ [BZ #23822]
+ * sysdeps/ia64/fpu/e_exp2f.S (exp2f): Use WEAK_LIBM_ENTRY.
+ * sysdeps/ia64/fpu/e_log2f.S (log2f): Likewise.
+ * sysdeps/ia64/fpu/e_exp2f.S (powf): Likewise.
+
+2018-10-25 Florian Weimer <fweimer@redhat.com>
+
+ [BZ #23562]
+ [BZ #23821]
+ XFAIL siginfo_t si_band conform test on sparc64.
+ * sysdeps/unix/sysv/linux/sparc/bits/siginfo-arch.h
+ (__SI_BAND_TYPE): Only override long int default type on sparc64.
+ * sysdeps/unix/sysv/linux/sparc/sparc64/Makefile
+ (conformtest-xfail-conds): Add sparc64-linux.
+ * conform/data/signal.h-data (siginfo_t): XFAIL si_band test on
+ sparc64.
+ * conform/data/sys/wait.h-data (siginfo_t): Likewise.
+
+2018-10-19 Ilya Yu. Malakhov <malakhov@mcst.ru>
+
+ [BZ #23562]
+ * sysdeps/unix/sysv/linux/bits/types/siginfo_t.h
+ (struct siginfo_t): Use correct type for si_band.
+
+2018-10-17 Stefan Liebler <stli@linux.ibm.com>
+
+ [BZ #23275]
+ * nptl/tst-mutex10.c: New File.
+ * nptl/Makefile (tests): Add tst-mutex10.
+ (tst-mutex10-ENV): New variable.
+ * sysdeps/unix/sysv/linux/s390/force-elision.h: (FORCE_ELISION):
+ Ensure that elision path is used if elision is available.
+ * sysdeps/unix/sysv/linux/powerpc/force-elision.h (FORCE_ELISION):
+ Likewise.
+ * sysdeps/unix/sysv/linux/x86/force-elision.h: (FORCE_ELISION):
+ Likewise.
+ * nptl/pthreadP.h (PTHREAD_MUTEX_TYPE, PTHREAD_MUTEX_TYPE_ELISION)
+ (PTHREAD_MUTEX_PSHARED): Use atomic_load_relaxed.
+ * nptl/pthread_mutex_consistent.c (pthread_mutex_consistent): Likewise.
+ * nptl/pthread_mutex_getprioceiling.c (pthread_mutex_getprioceiling):
+ Likewise.
+ * nptl/pthread_mutex_lock.c (__pthread_mutex_lock_full)
+ (__pthread_mutex_cond_lock_adjust): Likewise.
+ * nptl/pthread_mutex_setprioceiling.c (pthread_mutex_setprioceiling):
+ Likewise.
+ * nptl/pthread_mutex_timedlock.c (__pthread_mutex_timedlock): Likewise.
+ * nptl/pthread_mutex_trylock.c (__pthread_mutex_trylock): Likewise.
+ * nptl/pthread_mutex_unlock.c (__pthread_mutex_unlock_full): Likewise.
+ * sysdeps/nptl/bits/thread-shared-types.h (struct __pthread_mutex_s):
+ Add comments.
+ * nptl/pthread_mutex_destroy.c (__pthread_mutex_destroy):
+ Use atomic_load_relaxed and atomic_store_relaxed.
+ * nptl/pthread_mutex_init.c (__pthread_mutex_init):
+ Use atomic_store_relaxed.
+
+2018-10-09 H.J. Lu <hongjiu.lu@intel.com>
+
+ [BZ #23716]
+ * sysdeps/i386/dl-cet.c: Removed.
+ * sysdeps/i386/dl-machine.h (_dl_runtime_resolve_shstk): New
+ prototype.
+ (_dl_runtime_profile_shstk): Likewise.
+ (elf_machine_runtime_setup): Use _dl_runtime_profile_shstk or
+ _dl_runtime_resolve_shstk if SHSTK is enabled by kernel.
+
+2018-10-09 Rafal Luzynski <digitalfreak@lingonborough.com>
+
+ [BZ #20209]
+ * localedata/locales/kl_GL: (abday): Fix spelling of Sun (Sunday),
+ should be "sap" rather than "sab".
+ (day): Fix spelling of Sunday, should be "sapaat" rather than
+ "sabaat".
+
+2018-09-28 Adhemerval Zanella <adhemerval.zanella@linaro.org>
+
+ [BZ #23579]
+ * misc/tst-preadvwritev2-common.c (do_test_with_invalid_fd,
+ do_test_with_invalid_iov): New tests.
+ * misc/tst-preadvwritev2.c, misc/tst-preadvwritev64v2.c (do_test):
+ Call do_test_with_invalid_fd and do_test_with_invalid_iov.
+ * sysdeps/unix/sysv/linux/preadv2.c (preadv2): Use fallback code iff
+ errno is ENOSYS.
+ * sysdeps/unix/sysv/linux/preadv64v2.c (preadv64v2): Likewise.
+ * sysdeps/unix/sysv/linux/pwritev2.c (pwritev2): Likewise.
+ * sysdeps/unix/sysv/linux/pwritev64v2.c (pwritev64v2): Likewise.
+ * NEWS: Add bug fixed.
+
+2018-09-27 Andreas Schwab <schwab@suse.de>
+
+ [BZ #23717]
+ * stdlib/tst-setcontext9.c (f1a): Make st2 static.
+ (do_test): Make st1 static.
+
+2018-09-21 H.J. Lu <hongjiu.lu@intel.com>
+ Xuepeng Guo <xuepeng.guo@intel.com>
+
+ [BZ #23606]
+ * sysdeps/i386/start.S: Include <sysdep.h>
+ (_start): Use ENTRY/END to insert ENDBR32 at entry when CET is
+ enabled. Add cfi_undefined (eip).
+
+2018-09-19 Wilco Dijkstra <wdijkstr@arm.com>
+
+ [BZ #23637]
+ * string/test-strstr.c (pr23637): New function.
+ (test_main): Add tests with longer needles.
+ * string/strcasestr.c (AVAILABLE): Fix readahead distance.
+ * string/strstr.c (AVAILABLE): Likewise.
+
+2018-09-19 Carlos O'Donell <carlos@redhat.com>
+
+ * stdlib/tst-setcontext9.c (f1): Rename to...
+ (f1a): ... this.
+ (f1b): New function implementing lower half of f1 in alternate stack.
+
+2018-09-20 Florian Weimer <fweimer@redhat.com>
+
+ * misc/tst-gethostid.c: New file.
+ * misc/Makefile [$(build-shared)] (tests): Add tst-gethostid.
+ (tst-gethostid): Link with -ldl.
+
+2018-09-20 Mingli Yu <Mingli.Yu@windriver.com>
+
+ * sysdeps/unix/sysv/linux/gethostid.c (gethostid): Check for NULL
+ value from gethostbyname_r.
+
+2018-09-06 Stefan Liebler <stli@linux.ibm.com>
+
+ * sysdeps/unix/sysv/linux/spawni.c (maybe_script_execute):
+ Increment size of new_argv by one.
+
+2018-08-28 Florian Weimer <fweimer@redhat.com>
+
+ [BZ #23578]
+ * posix/tst-regcomp-truncated.c: New file.
+ * posix/Makefile (tests): Add it.
+ (tst-regcomp-truncated.out): Depend on generated locales.
+
+2018-08-25 Paul Eggert <eggert@cs.ucla.edu>
+
+ [BZ #23578]
+ regex: fix uninitialized memory access
+ I introduced this bug into gnulib in commit
+ 8335a4d6c7b4448cd0bcb6d0bebf1d456bcfdb17 dated 2006-04-10;
+ eventually it was merged into glibc. The bug was found by
+ project-repo <bugs@feusi.co> and reported here:
+ https://lists.gnu.org/r/sed-devel/2018-08/msg00017.html
+ Diagnosis and draft fix reported by Assaf Gordon here:
+ https://lists.gnu.org/r/bug-gnulib/2018-08/msg00071.html
+ https://lists.gnu.org/r/bug-gnulib/2018-08/msg00142.html
+ * posix/regex_internal.c (build_wcs_upper_buffer):
+ Fix bug when mbrtowc returns 0.
+
+2018-08-27 Martin Kuchta <martin.kuchta@netapp.com>
+ Torvald Riegel <triegel@redhat.com>
+
+ [BZ #23538]
+ * nptl/pthread_cond_common.c (__condvar_quiesce_and_switch_g1):
+ Update r to include the set wake-request flag if waiters are
+ remaining after spinning.
+
+2018-08-03 DJ Delorie <dj@redhat.com>
+
+ * sysdeps/riscv/rvf/math_private.h (libc_feholdexcept_setround_riscv):
+ Move libc_fesetround_riscv after libc_feholdexcept_riscv.
+
+ * sysdeps/riscv/rv64/rvd/libm-test-ulps: Update.
+
+2018-08-14 Florian Weimer <fweimer@redhat.com>
+
+ [BZ #23521]
+ [BZ #23522]
+ * nss/nss_files/files-alias.c (get_next_alias): During :include:
+ processing, bail out if no room, and close the stream before
+ returning ERANGE.
+ * nss/Makefile (tests): Add tst-nss-files-alias-leak.
+ (tst-nss-files-alias-leak): Link with libdl.
+ (tst-nss-files-alias-leak.out): Depend on nss_files.
+
+ * nss/tst-nss-files-alias-leak.c: New file.
+
+2018-08-14 Florian Weimer <fweimer@redhat.com>
+
+ * nscd/nscd_conf.c (nscd_parse_file): Deallocate old storage for
+ server_user, stat_user.
+
+2018-08-13 Florian Weimer <fweimer@redhat.com>
+
+ * misc/error.c (error): Add missing va_end call.
+ (error_at_line): Likewise.
+
+2018-08-10 Florian Weimer <fweimer@redhat.com>
+
+ [BZ #23497]
+ * sysdeps/unix/sysv/linux/getdents64.c (handle_overflow): New
+ function.
+ (__old_getdents64): Use getdents64. Convert entries without
+ moving them.
+ * sysdeps/unix/sysv/linux/tst-readdir64-compat.c: New file.
+ * sysdeps/unix/sysv/linux/Makefile (tests-internal): Add
+ tst-readdir64-compat.
+
+2018-08-08 Samuel Thibault <samuel.thibault@ens-lyon.org>
+
+ * htl/Versions (__pthread_getspecific, __pthread_setspecific): Add
+ symbols.
+ * sysdeps/htl/pthreadP.h [IS_IN (libpthread)] (__pthread_getspecific,
+ __pthread_setspecific): Add hidden proto.
+ * sysdeps/htl/pt-getspecific.c (__pthread_getspecific): Add hidden def.
+ * sysdeps/htl/pt-setspecific.c (__pthread_setspecific): Add hidden def.
+
2018-08-01 Carlos O'Donel <carlos@redhat.com>
* version.h (RELEASE): Set to "stable".
Please send GNU C library bug reports via <https://sourceware.org/bugzilla/>
using `glibc' in the "product" field.
\f
+Version 2.28.1
+
+The following bugs are resolved with this release:
+
+ [20209] localedata: Spelling mistake for Sunday in Greenlandic kl_GL
+ [22927] libanl: properly cleanup if first helper thread creation failed
+ [23400] stdlib/test-bz22786.c creates temporary files in glibc source tree
+ [23497] readdir64@GLIBC_2.1 cannot parse the kernel directory stream
+ [23509] CET enabled glibc is incompatible with the older linker
+ [23521] nss_files aliases database file stream leak
+ [23538] pthread_cond_broadcast: Fix waiters-after-spinning case
+ [23562] signal: Use correct type for si_band in siginfo_t
+ [23578] regex: Fix memory overread in re_compile_pattern
+ [23579] libc: Errors misreported in preadv2
+ [23606] Missing ENDBR32 in sysdeps/i386/start.S
+ [23679] gethostid: Missing NULL check for gethostbyname_r result
+ [23709] Fix CPU string flags for Haswell-type CPUs
+ [23717] Fix stack overflow in stdlib/tst-setcontext9
+ [23821] si_band in siginfo_t has wrong type long int on sparc64
+ [23822] ia64 static libm.a is missing exp2f, log2f and powf symbols
+ [23927] Linux if_nametoindex() does not close descriptor (CVE-2018-19591)
+
+Security related changes:
+
+ CVE-2018-19591: A file descriptor leak in if_nametoindex can lead to a
+ denial of service due to resource exhaustion when processing getaddrinfo
+ calls with crafted host names. Reported by Guido Vranken.
+\f
Version 2.28
Major new features:
element siginfo_t uid_t si_uid
element siginfo_t {void*} si_addr
element siginfo_t int si_status
-element siginfo_t long si_band
+// Bug 23821: si_band has type int on sparc64.
+xfail[sparc64-linux]-element siginfo_t long si_band
# endif
# ifndef XPG42
element siginfo_t {union sigval} si_value
element siginfo_t uid_t si_uid
element siginfo_t {void*} si_addr
element siginfo_t int si_status
-element siginfo_t long si_band
+// Bug 23821: si_band has type int on sparc64.
+xfail[sparc64-linux]-element siginfo_t long si_band
# ifndef XPG42
element siginfo_t {union sigval} si_value
# endif
Dl_info info;
if (_dl_addr (check_free, &info, &map, NULL) != 0 && map->l_ns == 0)
#endif
- free ((char *) rec->errstring);
+ {
+ free ((char *) rec->errstring);
+ rec->errstring = NULL;
+ }
}
}
/* This is really only for debugging. */
if (NSS_STATUS_TRYAGAIN > status || status > NSS_STATUS_RETURN)
- __libc_fatal ("illegal status in internal_getgrouplist");
+ __libc_fatal ("Illegal status in internal_getgrouplist.\n");
/* For compatibility reason we will continue to look for more
entries using the next service even though data has already
__cthread_keycreate;
__cthread_getspecific;
__cthread_setspecific;
+ __pthread_getspecific;
+ __pthread_setspecific;
__pthread_getattr_np;
__pthread_attr_getstack;
}
do_backtrace = 1 << 1 /* Backtrace. */
};
-/* Print out MESSAGE on the error output and abort. */
+/* Print out MESSAGE (which should end with a newline) on the error output
+ and abort. */
extern void __libc_fatal (const char *__message)
__attribute__ ((__noreturn__));
extern void __libc_message (enum __libc_message_action action,
return 0;
}
+#define TIMEOUT 100
#define PREPARE prepare
#include <support/test-driver.c>
END LC_NUMERIC
LC_TIME
-abday "sab";"ata";/
+abday "sap";"ata";/
"mar";"pin";/
"sis";"tal";/
"arf"
-day "sabaat";/
+day "sapaat";/
"ataasinngorneq";/
"marlunngorneq";/
"pingasunngorneq";/
tst-malloc_info \
tst-malloc-too-large \
tst-malloc-stats-cancellation \
+ tst-tcfree1 tst-tcfree2 \
tests-static := \
tst-interpose-static-nothread \
typedef struct tcache_entry
{
struct tcache_entry *next;
+ /* This field exists to detect double frees. */
+ struct tcache_perthread_struct *key;
} tcache_entry;
/* There is one of these for each thread, which contains the
{
tcache_entry *e = (tcache_entry *) chunk2mem (chunk);
assert (tc_idx < TCACHE_MAX_BINS);
+
+ /* Mark this chunk as "in the tcache" so the test in _int_free will
+ detect a double free. */
+ e->key = tcache;
+
e->next = tcache->entries[tc_idx];
tcache->entries[tc_idx] = e;
++(tcache->counts[tc_idx]);
assert (tcache->entries[tc_idx] > 0);
tcache->entries[tc_idx] = e->next;
--(tcache->counts[tc_idx]);
+ e->key = NULL;
return (void *) e;
}
while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av))
{
bck = victim->bk;
- if (__builtin_expect (chunksize_nomask (victim) <= 2 * SIZE_SZ, 0)
- || __builtin_expect (chunksize_nomask (victim)
- > av->system_mem, 0))
- malloc_printerr ("malloc(): memory corruption");
size = chunksize (victim);
+ mchunkptr next = chunk_at_offset (victim, size);
+
+ if (__glibc_unlikely (size <= 2 * SIZE_SZ)
+ || __glibc_unlikely (size > av->system_mem))
+ malloc_printerr ("malloc(): invalid size (unsorted)");
+ if (__glibc_unlikely (chunksize_nomask (next) < 2 * SIZE_SZ)
+ || __glibc_unlikely (chunksize_nomask (next) > av->system_mem))
+ malloc_printerr ("malloc(): invalid next size (unsorted)");
+ if (__glibc_unlikely ((prev_size (next) & ~(SIZE_BITS)) != size))
+ malloc_printerr ("malloc(): mismatching next->prev_size (unsorted)");
+ if (__glibc_unlikely (bck->fd != victim)
+ || __glibc_unlikely (victim->fd != unsorted_chunks (av)))
+ malloc_printerr ("malloc(): unsorted double linked list corrupted");
+ if (__glibc_unlikely (prev_inuse(next)))
+ malloc_printerr ("malloc(): invalid next->prev_inuse (unsorted)");
/*
If a small request, try to use last remainder if it is the
victim = av->top;
size = chunksize (victim);
+ if (__glibc_unlikely (size > av->system_mem))
+ malloc_printerr ("malloc(): corrupted top size");
+
if ((unsigned long) (size) >= (unsigned long) (nb + MINSIZE))
{
remainder_size = size - nb;
#if USE_TCACHE
{
size_t tc_idx = csize2tidx (size);
-
- if (tcache
- && tc_idx < mp_.tcache_bins
- && tcache->counts[tc_idx] < mp_.tcache_count)
+ if (tcache != NULL && tc_idx < mp_.tcache_bins)
{
- tcache_put (p, tc_idx);
- return;
+ /* Check to see if it's already in the tcache. */
+ tcache_entry *e = (tcache_entry *) chunk2mem (p);
+
+ /* This test succeeds on double free. However, we don't 100%
+ trust it (it also matches random payload data at a 1 in
+ 2^<size_t> chance), so verify it's not an unlikely
+ coincidence before aborting. */
+ if (__glibc_unlikely (e->key == tcache))
+ {
+ tcache_entry *tmp;
+ LIBC_PROBE (memory_tcache_double_free, 2, e, tc_idx);
+ for (tmp = tcache->entries[tc_idx];
+ tmp;
+ tmp = tmp->next)
+ if (tmp == e)
+ malloc_printerr ("free(): double free detected in tcache 2");
+ /* If we get here, it was a coincidence. We've wasted a
+ few cycles, but don't abort. */
+ }
+
+ if (tcache->counts[tc_idx] < mp_.tcache_count)
+ {
+ tcache_put (p, tc_idx);
+ return;
+ }
}
}
#endif
prevsize = prev_size (p);
size += prevsize;
p = chunk_at_offset(p, -((long) prevsize));
+ if (__glibc_unlikely (chunksize(p) != prevsize))
+ malloc_printerr ("corrupted size vs. prev_size while consolidating");
unlink(av, p, bck, fwd);
}
prevsize = prev_size (p);
size += prevsize;
p = chunk_at_offset(p, -((long) prevsize));
+ if (__glibc_unlikely (chunksize(p) != prevsize))
+ malloc_printerr ("corrupted size vs. prev_size in fastbins");
unlink(av, p, bck, fwd);
}
--- /dev/null
+/* Test that malloc tcache catches double free.
+ Copyright (C) 2018 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <error.h>
+#include <limits.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/signal.h>
+
+static int
+do_test (void)
+{
+ /* Do one allocation of any size that fits in tcache. */
+ char * volatile x = malloc (32);
+
+ free (x); // puts in tcache
+ free (x); // should abort
+
+ printf("FAIL: tcache double free not detected\n");
+ return 1;
+}
+
+#define TEST_FUNCTION do_test
+#define EXPECTED_SIGNAL SIGABRT
+#include <support/test-driver.c>
--- /dev/null
+/* Test that malloc tcache catches double free.
+ Copyright (C) 2018 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <error.h>
+#include <limits.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/signal.h>
+
+static int
+do_test (void)
+{
+ char * volatile ptrs[20];
+ int i;
+
+ /* Allocate enough small chunks so that when we free them all, the tcache
+ is full, and the first one we freed is at the end of its linked list. */
+#define COUNT 20
+ for (i=0; i<COUNT; i++)
+ ptrs[i] = malloc (20);
+ for (i=0; i<COUNT; i++)
+ free (ptrs[i]);
+ free (ptrs[0]);
+
+ printf("FAIL: tcache double free\n");
+ return 1;
+}
+
+#define TEST_FUNCTION do_test
+#define EXPECTED_SIGNAL SIGABRT
+#include <support/test-driver.c>
tst-preadvwritev tst-preadvwritev64 tst-makedev tst-empty \
tst-preadvwritev2 tst-preadvwritev64v2
+# Tests which need libdl.
+ifeq (yes,$(build-shared))
+tests += tst-gethostid
+endif
+
tests-internal := tst-atomic tst-atomic-long tst-allocate_once
tests-static := tst-empty
$(objpfx)tst-allocate_once-mem.out: $(objpfx)tst-allocate_once.out
$(common-objpfx)malloc/mtrace $(objpfx)tst-allocate_once.mtrace > $@; \
$(evaluate-test)
+
+$(objpfx)tst-gethostid: $(libdl)
va_start (args, message);
error_tail (status, errnum, message, args);
+ va_end (args);
#ifdef _LIBC
_IO_funlockfile (stderr);
va_start (args, message);
error_tail (status, errnum, message, args);
+ va_end (args);
#ifdef _LIBC
_IO_funlockfile (stderr);
--- /dev/null
+/* Basic test for gethostid.
+ Copyright (C) 2018 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <gnu/lib-names.h>
+#include <nss.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/namespace.h>
+#include <support/support.h>
+#include <support/temp_file.h>
+#include <support/xdlfcn.h>
+#include <support/xstdio.h>
+#include <support/xunistd.h>
+#include <unistd.h>
+
+/* Initial test is run outside a chroot, to increase the likelihood of
+ success. */
+static void
+outside_chroot (void *closure)
+{
+ long id = gethostid ();
+ printf ("info: host ID outside chroot: 0x%lx\n", id);
+}
+
+/* The same, but this time perform a chroot operation. */
+static void
+in_chroot (void *closure)
+{
+ const char *chroot_path = closure;
+ xchroot (chroot_path);
+ long id = gethostid ();
+ printf ("info: host ID in chroot: 0x%lx\n", id);
+}
+
+static int
+do_test (void)
+{
+ support_isolate_in_subprocess (outside_chroot, NULL);
+
+ /* Now run the test inside a chroot. */
+ support_become_root ();
+ if (!support_can_chroot ())
+ /* Cannot perform further tests. */
+ return 0;
+
+ /* Only use nss_files. */
+ __nss_configure_lookup ("hosts", "files");
+
+ /* Load the DSO outside of the chroot. */
+ xdlopen (LIBNSS_FILES_SO, RTLD_LAZY);
+
+ char *chroot_dir = support_create_temp_directory ("tst-gethostid-");
+ support_isolate_in_subprocess (in_chroot, chroot_dir);
+
+ /* Tests with /etc/hosts in the chroot. */
+ {
+ char *path = xasprintf ("%s/etc", chroot_dir);
+ add_temp_file (path);
+ xmkdir (path, 0777);
+ free (path);
+ path = xasprintf ("%s/etc/hosts", chroot_dir);
+ add_temp_file (path);
+
+ FILE *fp = xfopen (path, "w");
+ xfclose (fp);
+ printf ("info: chroot test with an empty /etc/hosts file\n");
+ support_isolate_in_subprocess (in_chroot, chroot_dir);
+
+ char hostname[1024];
+ int ret = gethostname (hostname, sizeof (hostname));
+ if (ret < 0)
+ printf ("warning: invalid result from gethostname: %d\n", ret);
+ else if (strlen (hostname) == 0)
+ puts ("warning: gethostname returned empty string");
+ else
+ {
+ printf ("info: chroot test with IPv6 address in /etc/hosts for: %s\n",
+ hostname);
+ fp = xfopen (path, "w");
+ /* Use an IPv6 address to induce another lookup failure. */
+ fprintf (fp, "2001:db8::1 %s\n", hostname);
+ xfclose (fp);
+ support_isolate_in_subprocess (in_chroot, chroot_dir);
+ }
+ free (path);
+ }
+ free (chroot_dir);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
#include <limits.h>
#include <support/check.h>
-static void
-do_test_with_invalid_flags (void)
-{
#ifndef RWF_HIPRI
# define RWF_HIPRI 0
#endif
#endif
#define RWF_SUPPORTED (RWF_HIPRI | RWF_DSYNC | RWF_SYNC | RWF_NOWAIT \
| RWF_APPEND)
+
+static void
+do_test_with_invalid_fd (void)
+{
+ char buf[256];
+ struct iovec iov = { buf, sizeof buf };
+
+ /* Check with flag being 0 to use the fallback code which calls pwritev
+ or writev. */
+ TEST_VERIFY (preadv2 (-1, &iov, 1, -1, 0) == -1);
+ TEST_COMPARE (errno, EBADF);
+ TEST_VERIFY (pwritev2 (-1, &iov, 1, -1, 0) == -1);
+ TEST_COMPARE (errno, EBADF);
+
+ /* Same tests as before but with flags being different than 0. Since
+ there is no emulation for any flag value, fallback code returns
+ ENOTSUP. This is different running on a kernel with preadv2/pwritev2
+ support, where EBADF is returned). */
+ TEST_VERIFY (preadv2 (-1, &iov, 1, 0, RWF_HIPRI) == -1);
+ TEST_VERIFY (errno == EBADF || errno == ENOTSUP);
+ TEST_VERIFY (pwritev2 (-1, &iov, 1, 0, RWF_HIPRI) == -1);
+ TEST_VERIFY (errno == EBADF || errno == ENOTSUP);
+}
+
+static void
+do_test_with_invalid_iov (void)
+{
+ {
+ char buf[256];
+ struct iovec iov;
+
+ iov.iov_base = buf;
+ iov.iov_len = (size_t)SSIZE_MAX + 1;
+
+ TEST_VERIFY (preadv2 (temp_fd, &iov, 1, 0, 0) == -1);
+ TEST_COMPARE (errno, EINVAL);
+ TEST_VERIFY (pwritev2 (temp_fd, &iov, 1, 0, 0) == -1);
+ TEST_COMPARE (errno, EINVAL);
+
+ /* Same as for invalid file descriptor tests, emulation fallback
+ first checks for flag value and return ENOTSUP. */
+ TEST_VERIFY (preadv2 (temp_fd, &iov, 1, 0, RWF_HIPRI) == -1);
+ TEST_VERIFY (errno == EINVAL || errno == ENOTSUP);
+ TEST_VERIFY (pwritev2 (temp_fd, &iov, 1, 0, RWF_HIPRI) == -1);
+ TEST_VERIFY (errno == EINVAL || errno == ENOTSUP);
+ }
+
+ {
+ /* An invalid iovec buffer should trigger an invalid memory access
+ or an error (Linux for instance returns EFAULT). */
+ struct iovec iov[IOV_MAX+1] = { 0 };
+
+ TEST_VERIFY (preadv2 (temp_fd, iov, IOV_MAX + 1, 0, RWF_HIPRI) == -1);
+ TEST_VERIFY (errno == EINVAL || errno == ENOTSUP);
+ TEST_VERIFY (pwritev2 (temp_fd, iov, IOV_MAX + 1, 0, RWF_HIPRI) == -1);
+ TEST_VERIFY (errno == EINVAL || errno == ENOTSUP);
+ }
+}
+
+static void
+do_test_with_invalid_flags (void)
+{
/* Set the next bit from the mask of all supported flags. */
int invalid_flag = RWF_SUPPORTED != 0 ? __builtin_clz (RWF_SUPPORTED) : 2;
invalid_flag = 0x1 << ((sizeof (int) * CHAR_BIT) - invalid_flag);
{
do_test_with_invalid_flags ();
do_test_without_offset ();
+ do_test_with_invalid_fd ();
+ do_test_with_invalid_iov ();
return do_test_with_offset (0);
}
{
do_test_with_invalid_flags ();
do_test_without_offset ();
+ do_test_with_invalid_fd ();
+ do_test_with_invalid_iov ();
return do_test_with_offset (0);
}
tests = tst-attr1 tst-attr2 tst-attr3 tst-default-attr \
tst-mutex1 tst-mutex2 tst-mutex3 tst-mutex4 tst-mutex5 tst-mutex6 \
- tst-mutex7 tst-mutex9 tst-mutex5a tst-mutex7a tst-mutex7robust \
- tst-mutexpi1 tst-mutexpi2 tst-mutexpi3 tst-mutexpi4 tst-mutexpi5 \
- tst-mutexpi5a tst-mutexpi6 tst-mutexpi7 tst-mutexpi7a \
+ tst-mutex7 tst-mutex9 tst-mutex10 tst-mutex5a tst-mutex7a \
+ tst-mutex7robust tst-mutexpi1 tst-mutexpi2 tst-mutexpi3 tst-mutexpi4 \
+ tst-mutexpi5 tst-mutexpi5a tst-mutexpi6 tst-mutexpi7 tst-mutexpi7a \
tst-mutexpi9 \
tst-spin1 tst-spin2 tst-spin3 tst-spin4 \
tst-cond1 tst-cond2 tst-cond3 tst-cond4 tst-cond5 tst-cond6 tst-cond7 \
$(objpfx)tst-compat-forwarder: $(objpfx)tst-compat-forwarder-mod.so
+tst-mutex10-ENV = GLIBC_TUNABLES=glibc.elision.enable=1
+
# The tests here better do not run in parallel
ifneq ($(filter %tests,$(MAKECMDGOALS)),)
.NOTPARALLEL:
};
#define PTHREAD_MUTEX_PSHARED_BIT 128
+/* See concurrency notes regarding __kind in struct __pthread_mutex_s
+ in sysdeps/nptl/bits/thread-shared-types.h. */
#define PTHREAD_MUTEX_TYPE(m) \
- ((m)->__data.__kind & 127)
+ (atomic_load_relaxed (&((m)->__data.__kind)) & 127)
/* Don't include NO_ELISION, as that type is always the same
as the underlying lock type. */
#define PTHREAD_MUTEX_TYPE_ELISION(m) \
- ((m)->__data.__kind & (127|PTHREAD_MUTEX_ELISION_NP))
+ (atomic_load_relaxed (&((m)->__data.__kind)) \
+ & (127 | PTHREAD_MUTEX_ELISION_NP))
#if LLL_PRIVATE == 0 && LLL_SHARED == 128
# define PTHREAD_MUTEX_PSHARED(m) \
- ((m)->__data.__kind & 128)
+ (atomic_load_relaxed (&((m)->__data.__kind)) & 128)
#else
# define PTHREAD_MUTEX_PSHARED(m) \
- (((m)->__data.__kind & 128) ? LLL_SHARED : LLL_PRIVATE)
+ ((atomic_load_relaxed (&((m)->__data.__kind)) & 128) \
+ ? LLL_SHARED : LLL_PRIVATE)
#endif
/* The kernel when waking robust mutexes on exit never uses
{
/* There is still a waiter after spinning. Set the wake-request
flag and block. Relaxed MO is fine because this is just about
- this futex word. */
- r = atomic_fetch_or_relaxed (cond->__data.__g_refs + g1, 1);
+ this futex word.
+
+ Update r to include the set wake-request flag so that the upcoming
+ futex_wait only blocks if the flag is still set (otherwise, we'd
+ violate the basic client-side futex protocol). */
+ r = atomic_fetch_or_relaxed (cond->__data.__g_refs + g1, 1) | 1;
if ((r >> 1) > 0)
futex_wait_simple (cond->__data.__g_refs + g1, r, private);
struct timespec rt;
if (__clock_gettime (CLOCK_MONOTONIC, &rt) != 0)
__libc_fatal ("clock_gettime does not support "
- "CLOCK_MONOTONIC");
+ "CLOCK_MONOTONIC\n");
/* Convert the absolute timeout value to a relative
timeout. */
rt.tv_sec = abstime->tv_sec - rt.tv_sec;
int
pthread_mutex_consistent (pthread_mutex_t *mutex)
{
- /* Test whether this is a robust mutex with a dead owner. */
- if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0
+ /* Test whether this is a robust mutex with a dead owner.
+ See concurrency notes regarding __kind in struct __pthread_mutex_s
+ in sysdeps/nptl/bits/thread-shared-types.h. */
+ if ((atomic_load_relaxed (&(mutex->__data.__kind))
+ & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0
|| mutex->__data.__owner != PTHREAD_MUTEX_INCONSISTENT)
return EINVAL;
{
LIBC_PROBE (mutex_destroy, 1, mutex);
- if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0
+ /* See concurrency notes regarding __kind in struct __pthread_mutex_s
+ in sysdeps/nptl/bits/thread-shared-types.h. */
+ if ((atomic_load_relaxed (&(mutex->__data.__kind))
+ & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0
&& mutex->__data.__nusers != 0)
return EBUSY;
- /* Set to an invalid value. */
- mutex->__data.__kind = -1;
+ /* Set to an invalid value. Relaxed MO is enough as it is undefined behavior
+ if the mutex is used after it has been destroyed. But you can reinitialize
+ it with pthread_mutex_init. */
+ atomic_store_relaxed (&(mutex->__data.__kind), -1);
return 0;
}
int
pthread_mutex_getprioceiling (const pthread_mutex_t *mutex, int *prioceiling)
{
- if (__builtin_expect ((mutex->__data.__kind
+ /* See concurrency notes regarding __kind in struct __pthread_mutex_s
+ in sysdeps/nptl/bits/thread-shared-types.h. */
+ if (__builtin_expect ((atomic_load_relaxed (&(mutex->__data.__kind))
& PTHREAD_MUTEX_PRIO_PROTECT_NP) == 0, 0))
return EINVAL;
memset (mutex, '\0', __SIZEOF_PTHREAD_MUTEX_T);
/* Copy the values from the attribute. */
- mutex->__data.__kind = imutexattr->mutexkind & ~PTHREAD_MUTEXATTR_FLAG_BITS;
+ int mutex_kind = imutexattr->mutexkind & ~PTHREAD_MUTEXATTR_FLAG_BITS;
if ((imutexattr->mutexkind & PTHREAD_MUTEXATTR_FLAG_ROBUST) != 0)
{
return ENOTSUP;
#endif
- mutex->__data.__kind |= PTHREAD_MUTEX_ROBUST_NORMAL_NP;
+ mutex_kind |= PTHREAD_MUTEX_ROBUST_NORMAL_NP;
}
switch (imutexattr->mutexkind & PTHREAD_MUTEXATTR_PROTOCOL_MASK)
{
case PTHREAD_PRIO_INHERIT << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT:
- mutex->__data.__kind |= PTHREAD_MUTEX_PRIO_INHERIT_NP;
+ mutex_kind |= PTHREAD_MUTEX_PRIO_INHERIT_NP;
break;
case PTHREAD_PRIO_PROTECT << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT:
- mutex->__data.__kind |= PTHREAD_MUTEX_PRIO_PROTECT_NP;
+ mutex_kind |= PTHREAD_MUTEX_PRIO_PROTECT_NP;
int ceiling = (imutexattr->mutexkind
& PTHREAD_MUTEXATTR_PRIO_CEILING_MASK)
FUTEX_PRIVATE_FLAG FUTEX_WAKE. */
if ((imutexattr->mutexkind & (PTHREAD_MUTEXATTR_FLAG_PSHARED
| PTHREAD_MUTEXATTR_FLAG_ROBUST)) != 0)
- mutex->__data.__kind |= PTHREAD_MUTEX_PSHARED_BIT;
+ mutex_kind |= PTHREAD_MUTEX_PSHARED_BIT;
+
+ /* See concurrency notes regarding __kind in struct __pthread_mutex_s
+ in sysdeps/nptl/bits/thread-shared-types.h. */
+ atomic_store_relaxed (&(mutex->__data.__kind), mutex_kind);
/* Default values: mutex not used yet. */
// mutex->__count = 0; already done by memset
int
__pthread_mutex_lock (pthread_mutex_t *mutex)
{
+ /* See concurrency notes regarding mutex type which is loaded from __kind
+ in struct __pthread_mutex_s in sysdeps/nptl/bits/thread-shared-types.h. */
unsigned int type = PTHREAD_MUTEX_TYPE_ELISION (mutex);
LIBC_PROBE (mutex_entry, 1, mutex);
case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP:
case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP:
{
- int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP;
- int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP;
+ int kind, robust;
+ {
+ /* See concurrency notes regarding __kind in struct __pthread_mutex_s
+ in sysdeps/nptl/bits/thread-shared-types.h. */
+ int mutex_kind = atomic_load_relaxed (&(mutex->__data.__kind));
+ kind = mutex_kind & PTHREAD_MUTEX_KIND_MASK_NP;
+ robust = mutex_kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP;
+ }
if (robust)
{
case PTHREAD_MUTEX_PP_NORMAL_NP:
case PTHREAD_MUTEX_PP_ADAPTIVE_NP:
{
- int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP;
+ /* See concurrency notes regarding __kind in struct __pthread_mutex_s
+ in sysdeps/nptl/bits/thread-shared-types.h. */
+ int kind = atomic_load_relaxed (&(mutex->__data.__kind))
+ & PTHREAD_MUTEX_KIND_MASK_NP;
oldval = mutex->__data.__lock;
void
__pthread_mutex_cond_lock_adjust (pthread_mutex_t *mutex)
{
- assert ((mutex->__data.__kind & PTHREAD_MUTEX_PRIO_INHERIT_NP) != 0);
- assert ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0);
- assert ((mutex->__data.__kind & PTHREAD_MUTEX_PSHARED_BIT) == 0);
+ /* See concurrency notes regarding __kind in struct __pthread_mutex_s
+ in sysdeps/nptl/bits/thread-shared-types.h. */
+ int mutex_kind = atomic_load_relaxed (&(mutex->__data.__kind));
+ assert ((mutex_kind & PTHREAD_MUTEX_PRIO_INHERIT_NP) != 0);
+ assert ((mutex_kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0);
+ assert ((mutex_kind & PTHREAD_MUTEX_PSHARED_BIT) == 0);
/* Record the ownership. */
pid_t id = THREAD_GETMEM (THREAD_SELF, tid);
mutex->__data.__owner = id;
- if (mutex->__data.__kind == PTHREAD_MUTEX_PI_RECURSIVE_NP)
+ if (mutex_kind == PTHREAD_MUTEX_PI_RECURSIVE_NP)
++mutex->__data.__count;
}
#endif
pthread_mutex_setprioceiling (pthread_mutex_t *mutex, int prioceiling,
int *old_ceiling)
{
- /* The low bits of __kind aren't ever changed after pthread_mutex_init,
- so we don't need a lock yet. */
- if ((mutex->__data.__kind & PTHREAD_MUTEX_PRIO_PROTECT_NP) == 0)
+ /* See concurrency notes regarding __kind in struct __pthread_mutex_s
+ in sysdeps/nptl/bits/thread-shared-types.h. */
+ if ((atomic_load_relaxed (&(mutex->__data.__kind))
+ & PTHREAD_MUTEX_PRIO_PROTECT_NP) == 0)
return EINVAL;
/* See __init_sched_fifo_prio. */
/* We must not check ABSTIME here. If the thread does not block
abstime must not be checked for a valid value. */
+ /* See concurrency notes regarding mutex type which is loaded from __kind
+ in struct __pthread_mutex_s in sysdeps/nptl/bits/thread-shared-types.h. */
switch (__builtin_expect (PTHREAD_MUTEX_TYPE_ELISION (mutex),
PTHREAD_MUTEX_TIMED_NP))
{
case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP:
case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP:
{
- int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP;
- int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP;
+ int kind, robust;
+ {
+ /* See concurrency notes regarding __kind in struct __pthread_mutex_s
+ in sysdeps/nptl/bits/thread-shared-types.h. */
+ int mutex_kind = atomic_load_relaxed (&(mutex->__data.__kind));
+ kind = mutex_kind & PTHREAD_MUTEX_KIND_MASK_NP;
+ robust = mutex_kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP;
+ }
if (robust)
{
case PTHREAD_MUTEX_PP_NORMAL_NP:
case PTHREAD_MUTEX_PP_ADAPTIVE_NP:
{
- int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP;
+ /* See concurrency notes regarding __kind in struct __pthread_mutex_s
+ in sysdeps/nptl/bits/thread-shared-types.h. */
+ int kind = atomic_load_relaxed (&(mutex->__data.__kind))
+ & PTHREAD_MUTEX_KIND_MASK_NP;
oldval = mutex->__data.__lock;
int oldval;
pid_t id = THREAD_GETMEM (THREAD_SELF, tid);
+ /* See concurrency notes regarding mutex type which is loaded from __kind
+ in struct __pthread_mutex_s in sysdeps/nptl/bits/thread-shared-types.h. */
switch (__builtin_expect (PTHREAD_MUTEX_TYPE_ELISION (mutex),
PTHREAD_MUTEX_TIMED_NP))
{
case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP:
case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP:
{
- int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP;
- int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP;
+ int kind, robust;
+ {
+ /* See concurrency notes regarding __kind in struct __pthread_mutex_s
+ in sysdeps/nptl/bits/thread-shared-types.h. */
+ int mutex_kind = atomic_load_relaxed (&(mutex->__data.__kind));
+ kind = mutex_kind & PTHREAD_MUTEX_KIND_MASK_NP;
+ robust = mutex_kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP;
+ }
if (robust)
/* Note: robust PI futexes are signaled by setting bit 0. */
case PTHREAD_MUTEX_PP_NORMAL_NP:
case PTHREAD_MUTEX_PP_ADAPTIVE_NP:
{
- int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP;
+ /* See concurrency notes regarding __kind in struct __pthread_mutex_s
+ in sysdeps/nptl/bits/thread-shared-types.h. */
+ int kind = atomic_load_relaxed (&(mutex->__data.__kind))
+ & PTHREAD_MUTEX_KIND_MASK_NP;
oldval = mutex->__data.__lock;
attribute_hidden
__pthread_mutex_unlock_usercnt (pthread_mutex_t *mutex, int decr)
{
+ /* See concurrency notes regarding mutex type which is loaded from __kind
+ in struct __pthread_mutex_s in sysdeps/nptl/bits/thread-shared-types.h. */
int type = PTHREAD_MUTEX_TYPE_ELISION (mutex);
if (__builtin_expect (type &
~(PTHREAD_MUTEX_KIND_MASK_NP|PTHREAD_MUTEX_ELISION_FLAGS_NP), 0))
/* If the previous owner died and the caller did not succeed in
making the state consistent, mark the mutex as unrecoverable
and make all waiters. */
- if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0
+ /* See concurrency notes regarding __kind in struct __pthread_mutex_s
+ in sysdeps/nptl/bits/thread-shared-types.h. */
+ if ((atomic_load_relaxed (&(mutex->__data.__kind))
+ & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0
&& __builtin_expect (mutex->__data.__owner
== PTHREAD_MUTEX_INCONSISTENT, 0))
pi_notrecoverable:
newowner = PTHREAD_MUTEX_NOTRECOVERABLE;
- if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0)
+ /* See concurrency notes regarding __kind in struct __pthread_mutex_s
+ in sysdeps/nptl/bits/thread-shared-types.h. */
+ if ((atomic_load_relaxed (&(mutex->__data.__kind))
+ & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0)
{
continue_pi_robust:
/* Remove mutex from the list.
/* Unlock. Load all necessary mutex data before releasing the mutex
to not violate the mutex destruction requirements (see
lll_unlock). */
- int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP;
+ /* See concurrency notes regarding __kind in struct __pthread_mutex_s
+ in sysdeps/nptl/bits/thread-shared-types.h. */
+ int robust = atomic_load_relaxed (&(mutex->__data.__kind))
+ & PTHREAD_MUTEX_ROBUST_NORMAL_NP;
private = (robust
? PTHREAD_ROBUST_MUTEX_PSHARED (mutex)
: PTHREAD_MUTEX_PSHARED (mutex));
--- /dev/null
+/* Testing race while enabling lock elision.
+ Copyright (C) 2018 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <support/support.h>
+#include <support/xthread.h>
+
+static pthread_barrier_t barrier;
+static pthread_mutex_t mutex;
+static long long int iteration_count = 1000000;
+static unsigned int thread_count = 3;
+
+static void *
+thr_func (void *arg)
+{
+ long long int i;
+ for (i = 0; i < iteration_count; i++)
+ {
+ if ((uintptr_t) arg == 0)
+ {
+ xpthread_mutex_destroy (&mutex);
+ xpthread_mutex_init (&mutex, NULL);
+ }
+
+ xpthread_barrier_wait (&barrier);
+
+ /* Test if enabling lock elision works if it is enabled concurrently.
+ There was a race in FORCE_ELISION macro which leads to either
+ pthread_mutex_destroy returning EBUSY as the owner was recorded
+ by pthread_mutex_lock - in "normal mutex" code path - but was not
+ resetted in pthread_mutex_unlock - in "elision" code path.
+ Or it leads to the assertion in nptl/pthread_mutex_lock.c:
+ assert (mutex->__data.__owner == 0);
+ Please ensure that the test is run with lock elision:
+ export GLIBC_TUNABLES=glibc.elision.enable=1 */
+ xpthread_mutex_lock (&mutex);
+ xpthread_mutex_unlock (&mutex);
+
+ xpthread_barrier_wait (&barrier);
+ }
+ return NULL;
+}
+
+static int
+do_test (void)
+{
+ unsigned int i;
+ printf ("Starting %d threads to run %lld iterations.\n",
+ thread_count, iteration_count);
+
+ pthread_t *threads = xmalloc (thread_count * sizeof (pthread_t));
+ xpthread_barrier_init (&barrier, NULL, thread_count);
+ xpthread_mutex_init (&mutex, NULL);
+
+ for (i = 0; i < thread_count; i++)
+ threads[i] = xpthread_create (NULL, thr_func, (void *) (uintptr_t) i);
+
+ for (i = 0; i < thread_count; i++)
+ xpthread_join (threads[i]);
+
+ xpthread_barrier_destroy (&barrier);
+ free (threads);
+
+ return EXIT_SUCCESS;
+}
+
+#define OPT_ITERATIONS 10000
+#define OPT_THREADS 10001
+#define CMDLINE_OPTIONS \
+ { "iterations", required_argument, NULL, OPT_ITERATIONS }, \
+ { "threads", required_argument, NULL, OPT_THREADS },
+static void
+cmdline_process (int c)
+{
+ long long int arg = strtoll (optarg, NULL, 0);
+ switch (c)
+ {
+ case OPT_ITERATIONS:
+ if (arg > 0)
+ iteration_count = arg;
+ break;
+ case OPT_THREADS:
+ if (arg > 0 && arg < 100)
+ thread_count = arg;
+ break;
+ }
+}
+#define CMDLINE_PROCESS cmdline_process
+#define TIMEOUT 50
+#include <support/test-driver.c>
/* This is really only for debugging. */
if (NSS_STATUS_TRYAGAIN > status || status > NSS_STATUS_RETURN)
- __libc_fatal ("illegal status in internal_getgrouplist");
+ __libc_fatal ("Illegal status in internal_getgrouplist.\n");
any_success |= status == NSS_STATUS_SUCCESS;
static time_t
addgetnetgrentX (struct database_dyn *db, int fd, request_header *req,
const char *key, uid_t uid, struct hashentry *he,
- struct datahead *dh, struct dataset **resultp)
+ struct datahead *dh, struct dataset **resultp,
+ void **tofreep)
{
if (__glibc_unlikely (debug_level > 0))
{
size_t group_len = strlen (key) + 1;
struct name_list *first_needed
= alloca (sizeof (struct name_list) + group_len);
+ *tofreep = NULL;
if (netgroup_database == NULL
&& __nss_database_lookup ("netgroup", NULL, NULL, &netgroup_database))
memset (&data, '\0', sizeof (data));
buffer = xmalloc (buflen);
+ *tofreep = buffer;
first_needed->next = first_needed;
memcpy (first_needed->name, key, group_len);
data.needed_groups = first_needed;
}
out:
- free (buffer);
-
*resultp = dataset;
return timeout;
group, group_len,
db, uid);
time_t timeout;
+ void *tofree;
if (result != NULL)
- timeout = result->head.timeout;
+ {
+ timeout = result->head.timeout;
+ tofree = NULL;
+ }
else
{
request_header req_get =
.key_len = group_len
};
timeout = addgetnetgrentX (db, -1, &req_get, group, uid, NULL, NULL,
- &result);
+ &result, &tofree);
}
struct indataset
++dh->nreloads;
if (cacheable)
pthread_rwlock_unlock (&db->lock);
- return timeout;
+ goto out;
}
if (he == NULL)
dh->usable = false;
}
+ out:
+ free (tofree);
return timeout;
}
+static time_t
+addgetnetgrentX_ignore (struct database_dyn *db, int fd, request_header *req,
+ const char *key, uid_t uid, struct hashentry *he,
+ struct datahead *dh)
+{
+ struct dataset *ignore;
+ void *tofree;
+ time_t timeout = addgetnetgrentX (db, fd, req, key, uid, he, dh,
+ &ignore, &tofree);
+ free (tofree);
+ return timeout;
+}
+
void
addgetnetgrent (struct database_dyn *db, int fd, request_header *req,
void *key, uid_t uid)
{
- struct dataset *ignore;
-
- addgetnetgrentX (db, fd, req, key, uid, NULL, NULL, &ignore);
+ addgetnetgrentX_ignore (db, fd, req, key, uid, NULL, NULL);
}
.type = GETNETGRENT,
.key_len = he->len
};
- struct dataset *ignore;
-
- return addgetnetgrentX (db, -1, &req, db->data + he->key, he->owner, he, dh,
- &ignore);
+ return addgetnetgrentX_ignore
+ (db, -1, &req, db->data + he->key, he->owner, he, dh);
}
if (!arg1)
error (0, 0, _("Must specify user name for server-user option"));
else
- server_user = xstrdup (arg1);
+ {
+ free ((char *) server_user);
+ server_user = xstrdup (arg1);
+ }
}
else if (strcmp (entry, "stat-user") == 0)
{
error (0, 0, _("Must specify user name for stat-user option"));
else
{
+ free ((char *) stat_user);
stat_user = xstrdup (arg1);
struct passwd *pw = getpwnam (stat_user);
tests += tst-nss-files-hosts-erange
tests += tst-nss-files-hosts-multi
tests += tst-nss-files-hosts-getent
+tests += tst-nss-files-alias-leak
endif
# If we have a thread library then we can test cancellation against
$(objpfx)tst-nss-files-hosts-erange: $(libdl)
$(objpfx)tst-nss-files-hosts-multi: $(libdl)
$(objpfx)tst-nss-files-hosts-getent: $(libdl)
+$(objpfx)tst-nss-files-alias-leak: $(libdl)
+$(objpfx)tst-nss-files-alias-leak.out: $(objpfx)/libnss_files.so
{
while (! feof_unlocked (listfile))
{
+ if (room_left < 2)
+ {
+ free (old_line);
+ fclose (listfile);
+ goto no_more_room;
+ }
+
first_unused[room_left - 1] = '\xff';
line = fgets_unlocked (first_unused, room_left,
listfile);
if (first_unused[room_left - 1] != '\xff')
{
free (old_line);
+ fclose (listfile);
goto no_more_room;
}
+ __alignof__ (char *)))
{
free (old_line);
+ fclose (listfile);
goto no_more_room;
}
room_left -= ((first_unused - cp)
/* This is really only for debugging. */
if (__builtin_expect (NSS_STATUS_TRYAGAIN > status
|| status > NSS_STATUS_RETURN, 0))
- __libc_fatal ("illegal status in __nss_next");
+ __libc_fatal ("Illegal status in __nss_next.\n");
if (nss_next_action (*ni, status) == NSS_ACTION_RETURN)
return 1;
--- /dev/null
+/* Check for file descriptor leak in alias :include: processing (bug 23521).
+ Copyright (C) 2018 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <aliases.h>
+#include <array_length.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <gnu/lib-names.h>
+#include <nss.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/namespace.h>
+#include <support/support.h>
+#include <support/temp_file.h>
+#include <support/test-driver.h>
+#include <support/xstdio.h>
+#include <support/xunistd.h>
+
+static struct support_chroot *chroot_env;
+
+/* Number of the aliases for the "many" user. This must be large
+ enough to trigger reallocation for the pointer array, but result in
+ answers below the maximum size tried in do_test. */
+enum { many_aliases = 30 };
+
+static void
+prepare (int argc, char **argv)
+{
+ chroot_env = support_chroot_create
+ ((struct support_chroot_configuration) { } );
+
+ char *path = xasprintf ("%s/etc/aliases", chroot_env->path_chroot);
+ add_temp_file (path);
+ support_write_file_string
+ (path,
+ "user1: :include:/etc/aliases.user1\n"
+ "user2: :include:/etc/aliases.user2\n"
+ "comment: comment1, :include:/etc/aliases.comment\n"
+ "many: :include:/etc/aliases.many\n");
+ free (path);
+
+ path = xasprintf ("%s/etc/aliases.user1", chroot_env->path_chroot);
+ add_temp_file (path);
+ support_write_file_string (path, "alias1\n");
+ free (path);
+
+ path = xasprintf ("%s/etc/aliases.user2", chroot_env->path_chroot);
+ add_temp_file (path);
+ support_write_file_string (path, "alias1a, alias2\n");
+ free (path);
+
+ path = xasprintf ("%s/etc/aliases.comment", chroot_env->path_chroot);
+ add_temp_file (path);
+ support_write_file_string
+ (path,
+ /* The line must be longer than the line with the :include:
+ directive in /etc/aliases. */
+ "# Long line. ##############################################\n"
+ "comment2\n");
+ free (path);
+
+ path = xasprintf ("%s/etc/aliases.many", chroot_env->path_chroot);
+ add_temp_file (path);
+ FILE *fp = xfopen (path, "w");
+ for (int i = 0; i < many_aliases; ++i)
+ fprintf (fp, "a%d\n", i);
+ TEST_VERIFY_EXIT (! ferror (fp));
+ xfclose (fp);
+ free (path);
+}
+
+/* The names of the users to test. */
+static const char *users[] = { "user1", "user2", "comment", "many" };
+
+static void
+check_aliases (int id, const struct aliasent *e)
+{
+ TEST_VERIFY_EXIT (id >= 0 || id < array_length (users));
+ const char *name = users[id];
+ TEST_COMPARE_BLOB (e->alias_name, strlen (e->alias_name),
+ name, strlen (name));
+
+ switch (id)
+ {
+ case 0:
+ TEST_COMPARE (e->alias_members_len, 1);
+ TEST_COMPARE_BLOB (e->alias_members[0], strlen (e->alias_members[0]),
+ "alias1", strlen ("alias1"));
+ break;
+
+ case 1:
+ TEST_COMPARE (e->alias_members_len, 2);
+ TEST_COMPARE_BLOB (e->alias_members[0], strlen (e->alias_members[0]),
+ "alias1a", strlen ("alias1a"));
+ TEST_COMPARE_BLOB (e->alias_members[1], strlen (e->alias_members[1]),
+ "alias2", strlen ("alias2"));
+ break;
+
+ case 2:
+ TEST_COMPARE (e->alias_members_len, 2);
+ TEST_COMPARE_BLOB (e->alias_members[0], strlen (e->alias_members[0]),
+ "comment1", strlen ("comment1"));
+ TEST_COMPARE_BLOB (e->alias_members[1], strlen (e->alias_members[1]),
+ "comment2", strlen ("comment2"));
+ break;
+
+ case 3:
+ TEST_COMPARE (e->alias_members_len, many_aliases);
+ for (int i = 0; i < e->alias_members_len; ++i)
+ {
+ char alias[30];
+ int len = snprintf (alias, sizeof (alias), "a%d", i);
+ TEST_VERIFY_EXIT (len > 0);
+ TEST_COMPARE_BLOB (e->alias_members[i], strlen (e->alias_members[i]),
+ alias, len);
+ }
+ break;
+ }
+}
+
+static int
+do_test (void)
+{
+ /* Make sure we don't try to load the module in the chroot. */
+ if (dlopen (LIBNSS_FILES_SO, RTLD_NOW) == NULL)
+ FAIL_EXIT1 ("could not load " LIBNSS_FILES_SO ": %s", dlerror ());
+
+ /* Some of these descriptors will become unavailable if there is a
+ file descriptor leak. 10 is chosen somewhat arbitrarily. The
+ array must be longer than the number of files opened by nss_files
+ at the same time (currently that number is 2). */
+ int next_descriptors[10];
+ for (size_t i = 0; i < array_length (next_descriptors); ++i)
+ {
+ next_descriptors[i] = dup (0);
+ TEST_VERIFY_EXIT (next_descriptors[i] > 0);
+ }
+ for (size_t i = 0; i < array_length (next_descriptors); ++i)
+ xclose (next_descriptors[i]);
+
+ support_become_root ();
+ if (!support_can_chroot ())
+ return EXIT_UNSUPPORTED;
+
+ __nss_configure_lookup ("aliases", "files");
+
+ xchroot (chroot_env->path_chroot);
+
+ /* Attempt various buffer sizes. If the operation succeeds, we
+ expect correct data. */
+ for (int id = 0; id < array_length (users); ++id)
+ {
+ bool found = false;
+ for (size_t size = 1; size <= 1000; ++size)
+ {
+ void *buffer = malloc (size);
+ struct aliasent result;
+ struct aliasent *res;
+ errno = EINVAL;
+ int ret = getaliasbyname_r (users[id], &result, buffer, size, &res);
+ if (ret == 0)
+ {
+ if (res != NULL)
+ {
+ found = true;
+ check_aliases (id, res);
+ }
+ else
+ {
+ support_record_failure ();
+ printf ("error: failed lookup for user \"%s\", size %zu\n",
+ users[id], size);
+ }
+ }
+ else if (ret != ERANGE)
+ {
+ support_record_failure ();
+ printf ("error: invalid return code %d (user \%s\", size %zu)\n",
+ ret, users[id], size);
+ }
+ free (buffer);
+
+ /* Make sure that we did not have a file descriptor leak. */
+ for (size_t i = 0; i < array_length (next_descriptors); ++i)
+ {
+ int new_fd = dup (0);
+ if (new_fd != next_descriptors[i])
+ {
+ support_record_failure ();
+ printf ("error: descriptor %d at index %zu leaked"
+ " (user \"%s\", size %zu)\n",
+ next_descriptors[i], i, users[id], size);
+
+ /* Close unexpected descriptor, the leak probing
+ descriptors, and the leaked descriptor
+ next_descriptors[i]. */
+ xclose (new_fd);
+ for (size_t j = 0; j <= i; ++j)
+ xclose (next_descriptors[j]);
+ goto next_size;
+ }
+ }
+ for (size_t i = 0; i < array_length (next_descriptors); ++i)
+ xclose (next_descriptors[i]);
+
+ next_size:
+ ;
+ }
+ if (!found)
+ {
+ support_record_failure ();
+ printf ("error: user %s not found\n", users[id]);
+ }
+ }
+
+ support_chroot_free (chroot_env);
+ return 0;
+}
+
+#define PREPARE prepare
+#include <support/test-driver.c>
tst-posix_fadvise tst-posix_fadvise64 \
tst-sysconf-empty-chroot tst-glob_symlinks tst-fexecve \
tst-glob-tilde test-ssize-max tst-spawn4 bug-regex37 \
- bug-regex38
+ bug-regex38 tst-regcomp-truncated
tests-internal := bug-regex5 bug-regex20 bug-regex33 \
tst-rfc3484 tst-rfc3484-2 tst-rfc3484-3 \
tst-glob_lstat_compat tst-spawn4-compat
$(objpfx)tst-regexloc.out: $(gen-locales)
$(objpfx)tst-rxspencer.out: $(gen-locales)
$(objpfx)tst-rxspencer-no-utf8.out: $(gen-locales)
+$(objpfx)tst-regcomp-truncated.out: $(gen-locales)
endif
# If we will use the generic uname implementation, we must figure out what
mbclen = __mbrtowc (&wc,
((const char *) pstr->raw_mbs + pstr->raw_mbs_idx
+ byte_idx), remain_len, &pstr->cur_state);
- if (BE (mbclen < (size_t) -2, 1))
+ if (BE (0 < mbclen && mbclen < (size_t) -2, 1))
{
wchar_t wcu = __towupper (wc);
if (wcu != wc)
else
p = (const char *) pstr->raw_mbs + pstr->raw_mbs_idx + src_idx;
mbclen = __mbrtowc (&wc, p, remain_len, &pstr->cur_state);
- if (BE (mbclen < (size_t) -2, 1))
+ if (BE (0 < mbclen && mbclen < (size_t) -2, 1))
{
wchar_t wcu = __towupper (wc);
if (wcu != wc)
--- /dev/null
+/* Test compilation of truncated regular expressions.
+ Copyright (C) 2018 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* This test constructs various patterns in an attempt to trigger
+ over-reading the regular expression compiler, such as bug
+ 23578. */
+
+#include <array_length.h>
+#include <errno.h>
+#include <locale.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/next_to_fault.h>
+#include <support/support.h>
+#include <support/test-driver.h>
+#include <wchar.h>
+
+/* Locales to test. */
+static const char locales[][17] =
+ {
+ "C",
+ "en_US.UTF-8",
+ "de_DE.ISO-8859-1",
+ };
+
+/* Syntax options. Will be combined with other flags. */
+static const reg_syntax_t syntaxes[] =
+ {
+ RE_SYNTAX_EMACS,
+ RE_SYNTAX_AWK,
+ RE_SYNTAX_GNU_AWK,
+ RE_SYNTAX_POSIX_AWK,
+ RE_SYNTAX_GREP,
+ RE_SYNTAX_EGREP,
+ RE_SYNTAX_POSIX_EGREP,
+ RE_SYNTAX_POSIX_BASIC,
+ RE_SYNTAX_POSIX_EXTENDED,
+ RE_SYNTAX_POSIX_MINIMAL_EXTENDED,
+ };
+
+/* Trailing characters placed after the initial character. */
+static const char trailing_strings[][4] =
+ {
+ "",
+ "[",
+ "\\",
+ "[\\",
+ "(",
+ "(\\",
+ "\\(",
+ };
+
+static int
+do_test (void)
+{
+ /* Staging buffer for the constructed regular expression. */
+ char buffer[16];
+
+ /* Allocation used to detect over-reading by the regular expression
+ compiler. */
+ struct support_next_to_fault ntf
+ = support_next_to_fault_allocate (sizeof (buffer));
+
+ /* Arbitrary Unicode codepoint at which we stop generating
+ characters. We do not probe the whole range because that would
+ take too long due to combinatorical exploision as the result of
+ combination with other flags. */
+ static const wchar_t last_character = 0xfff;
+
+ for (size_t locale_idx = 0; locale_idx < array_length (locales);
+ ++ locale_idx)
+ {
+ if (setlocale (LC_ALL, locales[locale_idx]) == NULL)
+ {
+ support_record_failure ();
+ printf ("error: setlocale (\"%s\"): %m", locales[locale_idx]);
+ continue;
+ }
+ if (test_verbose > 0)
+ printf ("info: testing locale \"%s\"\n", locales[locale_idx]);
+
+ for (wchar_t wc = 0; wc <= last_character; ++wc)
+ {
+ char *after_wc;
+ if (wc == 0)
+ {
+ /* wcrtomb treats L'\0' in a special way. */
+ *buffer = '\0';
+ after_wc = &buffer[1];
+ }
+ else
+ {
+ mbstate_t ps = { };
+ size_t ret = wcrtomb (buffer, wc, &ps);
+ if (ret == (size_t) -1)
+ {
+ /* EILSEQ means that the target character set
+ cannot encode the character. */
+ if (errno != EILSEQ)
+ {
+ support_record_failure ();
+ printf ("error: wcrtomb (0x%x) failed: %m\n",
+ (unsigned) wc);
+ }
+ continue;
+ }
+ TEST_VERIFY_EXIT (ret != 0);
+ after_wc = &buffer[ret];
+ }
+
+ for (size_t trailing_idx = 0;
+ trailing_idx < array_length (trailing_strings);
+ ++trailing_idx)
+ {
+ char *after_trailing
+ = stpcpy (after_wc, trailing_strings[trailing_idx]);
+
+ for (int do_nul = 0; do_nul < 2; ++do_nul)
+ {
+ char *after_nul;
+ if (do_nul)
+ {
+ *after_trailing = '\0';
+ after_nul = &after_trailing[1];
+ }
+ else
+ after_nul = after_trailing;
+
+ size_t length = after_nul - buffer;
+
+ /* Make sure that the faulting region starts
+ after the used portion of the buffer. */
+ char *ntf_start = ntf.buffer + sizeof (buffer) - length;
+ memcpy (ntf_start, buffer, length);
+
+ for (const reg_syntax_t *psyntax = syntaxes;
+ psyntax < array_end (syntaxes); ++psyntax)
+ for (int do_icase = 0; do_icase < 2; ++do_icase)
+ {
+ re_syntax_options = *psyntax;
+ if (do_icase)
+ re_syntax_options |= RE_ICASE;
+
+ regex_t reg;
+ memset (®, 0, sizeof (reg));
+ const char *msg = re_compile_pattern
+ (ntf_start, length, ®);
+ if (msg != NULL)
+ {
+ if (test_verbose > 0)
+ {
+ char *quoted = support_quote_blob
+ (buffer, length);
+ printf ("info: compilation failed for pattern"
+ " \"%s\", syntax 0x%lx: %s\n",
+ quoted, re_syntax_options, msg);
+ free (quoted);
+ }
+ }
+ else
+ regfree (®);
+ }
+ }
+ }
+ }
+ }
+
+ support_next_to_fault_free (&ntf);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
/* We cannot create a thread in the moment and there is
also no thread running. This is a problem. `errno' is
set to EAGAIN if this is only a temporary problem. */
- assert (lastp->next == newp);
- lastp->next = NULL;
+ assert (requests == newp || lastp->next == newp);
+ if (lastp != NULL)
+ lastp->next = NULL;
+ else
+ requests = NULL;
requests_tail = lastp;
newp->next = freelist;
resolv_response_add_data (b, &rrtype, sizeof (rrtype));
}
break;
+ case 104:
+ send_ptr (b, qname, qclass, qtype, "host.example");
+ break;
default:
FAIL_EXIT1 ("invalid QNAME: %s (code %d)", qname, code);
}
"error: TRY_AGAIN\n");
check_netent ("code103.example", getnetbyname ("code103.example"),
"error: NO_RECOVERY\n");
+ /* Test bug #17630. */
+ check_netent ("code104.example", getnetbyname ("code104.example"),
+ "error: TRY_AGAIN\n");
/* Lookup by address, success cases. */
check_reverse (1,
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <support/blob_repeat.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/temp_file.h>
#include <support/test-driver.h>
#include <libc-diag.h>
static int
do_test (void)
{
- const char dir[] = "bz22786";
- const char lnk[] = "bz22786/symlink";
-
- rmdir (dir);
- if (mkdir (dir, 0755) != 0 && errno != EEXIST)
- {
- printf ("mkdir %s: %m\n", dir);
- return EXIT_FAILURE;
- }
- if (symlink (".", lnk) != 0 && errno != EEXIST)
- {
- printf ("symlink (%s, %s): %m\n", dir, lnk);
- return EXIT_FAILURE;
- }
-
- const size_t path_len = (size_t) INT_MAX + 1;
-
- DIAG_PUSH_NEEDS_COMMENT;
-#if __GNUC_PREREQ (7, 0)
- /* GCC 7 warns about too-large allocations; here we need such
- allocation to succeed for the test to work. */
- DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than=");
-#endif
- char *path = malloc (path_len);
- DIAG_POP_NEEDS_COMMENT;
+ char *dir = support_create_temp_directory ("bz22786.");
+ char *lnk = xasprintf ("%s/symlink", dir);
+ const size_t path_len = (size_t) INT_MAX + strlen (lnk) + 1;
+ struct support_blob_repeat repeat
+ = support_blob_repeat_allocate ("a", 1, path_len);
+ char *path = repeat.start;
if (path == NULL)
{
- printf ("malloc (%zu): %m\n", path_len);
+ printf ("Repeated allocation (%zu bytes): %m\n", path_len);
+ /* On 31-bit s390 the malloc will always fail as we do not have
+ so much memory, and we want to mark the test unsupported.
+ Likewise on systems with little physical memory the test will
+ fail and should be unsupported. */
return EXIT_UNSUPPORTED;
}
- /* Construct very long path = "bz22786/symlink/aaaa....." */
- char *p = mempcpy (path, lnk, sizeof (lnk) - 1);
+ TEST_VERIFY_EXIT (symlink (".", lnk) == 0);
+
+ /* Construct very long path = "/tmp/bz22786.XXXX/symlink/aaaa....." */
+ char *p = mempcpy (path, lnk, strlen (lnk));
*(p++) = '/';
- memset (p, 'a', path_len - (path - p) - 2);
- p[path_len - (path - p) - 1] = '\0';
+ p[path_len - (p - path) - 1] = '\0';
/* This call crashes before the fix for bz22786 on 32-bit platforms. */
p = realpath (path, NULL);
/* Cleanup. */
unlink (lnk);
- rmdir (dir);
+ support_blob_repeat_free (&repeat);
+ free (lnk);
+ free (dir);
return 0;
}
}
static void
-f1 (void)
+f1b (void)
{
- puts ("start f1");
- if (getcontext (&ctx[2]) != 0)
- {
- printf ("%s: getcontext: %m\n", __FUNCTION__);
- exit (EXIT_FAILURE);
- }
if (done)
{
- puts ("set context in f1");
+ puts ("set context in f1b");
if (setcontext (&ctx[3]) != 0)
{
printf ("%s: setcontext: %m\n", __FUNCTION__);
exit (EXIT_FAILURE);
}
}
+ exit (EXIT_FAILURE);
+}
+
+static void
+f1a (void)
+{
+ static char st2[32768];
+ puts ("start f1a");
+ if (getcontext (&ctx[2]) != 0)
+ {
+ printf ("%s: getcontext: %m\n", __FUNCTION__);
+ exit (EXIT_FAILURE);
+ }
+ ctx[2].uc_stack.ss_sp = st2;
+ ctx[2].uc_stack.ss_size = sizeof st2;
+ ctx[2].uc_link = &ctx[0];
+ makecontext (&ctx[2], (void (*) (void)) f1b, 0);
f2 ();
}
+/* The execution path through the test looks like this:
+ do_test (call)
+ -> "making contexts"
+ -> "swap contexts"
+ f1a (via swapcontext to ctx[1], with alternate stack)
+ -> "start f1a"
+ f2 (call)
+ -> "swap contexts in f2"
+ f1b (via swapcontext to ctx[2], with alternate stack)
+ -> "set context in f1b"
+ do_test (via setcontext to ctx[3], main stack)
+ -> "setcontext"
+ f2 (via setcontext to ctx[4], with alternate stack)
+ -> "end f2"
+
+ We must use an alternate stack for f1b, because if we don't then the
+ result of executing an earlier caller may overwrite registers
+ spilled to the stack in f2. */
static int
do_test (void)
{
- char st1[32768];
+ static char st1[32768];
puts ("making contexts");
if (getcontext (&ctx[0]) != 0)
{
ctx[1].uc_stack.ss_sp = st1;
ctx[1].uc_stack.ss_size = sizeof st1;
ctx[1].uc_link = &ctx[0];
- makecontext (&ctx[1], (void (*) (void)) f1, 0);
+ makecontext (&ctx[1], (void (*) (void)) f1a, 0);
puts ("swap contexts");
if (swapcontext (&ctx[3], &ctx[1]) != 0)
{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <support/blob_repeat.h>
+#include <support/test-driver.h>
#define EXPONENT "e-2147483649"
#define SIZE 214748364
static int
do_test (void)
{
- char *p = malloc (1 + SIZE + sizeof (EXPONENT));
- if (p == NULL)
+ struct support_blob_repeat repeat = support_blob_repeat_allocate
+ ("0", 1, 1 + SIZE + sizeof (EXPONENT));
+ if (repeat.size == 0)
{
- puts ("malloc failed, cannot test for overflow");
- return 0;
+ puts ("warning: memory allocation failed, cannot test for overflow");
+ return EXIT_UNSUPPORTED;
}
+ char *p = repeat.start;
p[0] = '1';
- memset (p + 1, '0', SIZE);
memcpy (p + 1 + SIZE, EXPONENT, sizeof (EXPONENT));
double d = strtod (p, NULL);
if (d != 0)
{
- printf ("strtod returned wrong value: %a\n", d);
+ printf ("error: strtod returned wrong value: %a\n", d);
return 1;
}
+ support_blob_repeat_free (&repeat);
return 0;
}
/* Two-Way algorithm. */
#define RETURN_TYPE char *
#define AVAILABLE(h, h_l, j, n_l) \
- (((j) + (n_l) <= (h_l)) || ((h_l) += __strnlen ((void*)((h) + (h_l)), 512), \
- (j) + (n_l) <= (h_l)))
+ (((j) + (n_l) <= (h_l)) \
+ || ((h_l) += __strnlen ((void*)((h) + (h_l)), (n_l) + 512), \
+ (j) + (n_l) <= (h_l)))
#define CHECK_EOL (1)
#define RET0_IF_0(a) if (!a) goto ret0
#define CANON_ELEMENT(c) TOLOWER (c)
#define RETURN_TYPE char *
#define AVAILABLE(h, h_l, j, n_l) \
- (((j) + (n_l) <= (h_l)) || ((h_l) += __strnlen ((void*)((h) + (h_l)), 512), \
- (j) + (n_l) <= (h_l)))
+ (((j) + (n_l) <= (h_l)) \
+ || ((h_l) += __strnlen ((void*)((h) + (h_l)), (n_l) + 512), \
+ (j) + (n_l) <= (h_l)))
#define CHECK_EOL (1)
#define RET0_IF_0(a) if (!a) goto ret0
#define FASTSEARCH(S,C,N) (void*) strchr ((void*)(S), (C))
}
}
+#define N 1024
+
+static void
+pr23637 (void)
+{
+ char *h = (char*) buf1;
+ char *n = (char*) buf2;
+
+ for (int i = 0; i < N; i++)
+ {
+ n[i] = 'x';
+ h[i] = ' ';
+ h[i + N] = 'x';
+ }
+
+ n[N] = '\0';
+ h[N * 2] = '\0';
+
+ /* Ensure we don't match at the first 'x'. */
+ h[0] = 'x';
+
+ char *exp_result = stupid_strstr (h, n);
+ FOR_EACH_IMPL (impl, 0)
+ check_result (impl, h, n, exp_result);
+}
+
static int
test_main (void)
{
check1 ();
check2 ();
+ pr23637 ();
printf ("%23s", "");
FOR_EACH_IMPL (impl, 0)
do_test (15, 9, hlen, klen, 1);
do_test (15, 15, hlen, klen, 0);
do_test (15, 15, hlen, klen, 1);
+
+ do_test (15, 15, hlen + klen * 4, klen * 4, 0);
+ do_test (15, 15, hlen + klen * 4, klen * 4, 1);
}
do_test (0, 0, page_size - 1, 16, 0);
extra-libs-noinstall := $(extra-libs)
libsupport-routines = \
+ blob_repeat \
check \
check_addrinfo \
check_dns_packet \
tests = \
README-testing \
tst-support-namespace \
+ tst-support_blob_repeat \
tst-support_capture_subprocess \
tst-support_format_dns_packet \
tst-support_quote_blob \
--- /dev/null
+/* Repeating a memory blob, with alias mapping optimization.
+ Copyright (C) 2018 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/blob_repeat.h>
+#include <support/check.h>
+#include <support/test-driver.h>
+#include <support/support.h>
+#include <support/xunistd.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <wchar.h>
+
+/* Small allocations should use malloc directly instead of the mmap
+ optimization because mappings carry a lot of overhead. */
+static const size_t maximum_small_size = 4 * 1024 * 1024;
+
+/* Internal helper for fill. */
+static void
+fill0 (char *target, const char *element, size_t element_size,
+ size_t count)
+{
+ while (count > 0)
+ {
+ memcpy (target, element, element_size);
+ target += element_size;
+ --count;
+ }
+}
+
+/* Fill the buffer at TARGET with COUNT copies of the ELEMENT_SIZE
+ bytes starting at ELEMENT. */
+static void
+fill (char *target, const char *element, size_t element_size,
+ size_t count)
+{
+ if (element_size == 0 || count == 0)
+ return;
+ else if (element_size == 1)
+ memset (target, element[0], count);
+ else if (element_size == sizeof (wchar_t))
+ {
+ wchar_t wc;
+ memcpy (&wc, element, sizeof (wc));
+ wmemset ((wchar_t *) target, wc, count);
+ }
+ else if (element_size < 1024 && count > 4096)
+ {
+ /* Use larger copies for really small element sizes. */
+ char buffer[8192];
+ size_t buffer_count = sizeof (buffer) / element_size;
+ fill0 (buffer, element, element_size, buffer_count);
+ while (count > 0)
+ {
+ size_t copy_count = buffer_count;
+ if (copy_count > count)
+ copy_count = count;
+ size_t copy_bytes = copy_count * element_size;
+ memcpy (target, buffer, copy_bytes);
+ target += copy_bytes;
+ count -= copy_count;
+ }
+ }
+ else
+ fill0 (target, element, element_size, count);
+}
+
+/* Use malloc instead of mmap for small allocations and unusual size
+ combinations. */
+static struct support_blob_repeat
+allocate_malloc (size_t total_size, const void *element, size_t element_size,
+ size_t count)
+{
+ void *buffer = malloc (total_size);
+ if (buffer == NULL)
+ return (struct support_blob_repeat) { 0 };
+ fill (buffer, element, element_size, count);
+ return (struct support_blob_repeat)
+ {
+ .start = buffer,
+ .size = total_size,
+ .use_malloc = true
+ };
+}
+
+/* Return the least common multiple of PAGE_SIZE and ELEMENT_SIZE,
+ avoiding overflow. This assumes that PAGE_SIZE is a power of
+ two. */
+static size_t
+minimum_stride_size (size_t page_size, size_t element_size)
+{
+ TEST_VERIFY_EXIT (page_size > 0);
+ TEST_VERIFY_EXIT (element_size > 0);
+
+ /* Compute the number of trailing zeros common to both sizes. */
+ unsigned int common_zeros = __builtin_ctzll (page_size | element_size);
+
+ /* In the product, this power of two appears twice, but in the least
+ common multiple, it appears only once. Therefore, shift one
+ factor. */
+ size_t multiple;
+ if (__builtin_mul_overflow (page_size >> common_zeros, element_size,
+ &multiple))
+ return 0;
+ return multiple;
+}
+
+/* Allocations larger than maximum_small_size potentially use mmap
+ with alias mappings. */
+static struct support_blob_repeat
+allocate_big (size_t total_size, const void *element, size_t element_size,
+ size_t count)
+{
+ unsigned long page_size = xsysconf (_SC_PAGESIZE);
+ size_t stride_size = minimum_stride_size (page_size, element_size);
+ if (stride_size == 0)
+ {
+ errno = EOVERFLOW;
+ return (struct support_blob_repeat) { 0 };
+ }
+
+ /* Ensure that the stride size is at least maximum_small_size. This
+ is necessary to reduce the number of distinct mappings. */
+ if (stride_size < maximum_small_size)
+ stride_size
+ = ((maximum_small_size + stride_size - 1) / stride_size) * stride_size;
+
+ if (stride_size > total_size)
+ /* The mmap optimization would not save anything. */
+ return allocate_malloc (total_size, element, element_size, count);
+
+ /* Reserve the memory region. If we cannot create the mapping,
+ there is no reason to set up the backing file. */
+ void *target = mmap (NULL, total_size, PROT_NONE,
+ MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+ if (target == MAP_FAILED)
+ return (struct support_blob_repeat) { 0 };
+
+ /* Create the backing file for the repeated mapping. Call mkstemp
+ directly to remove the resources backing the temporary file
+ immediately, once support_blob_repeat_free is called. Using
+ create_temp_file would result in a warning during post-test
+ cleanup. */
+ int fd;
+ {
+ char *temppath = xasprintf ("%s/support_blob_repeat-XXXXXX", test_dir);
+ fd = mkstemp (temppath);
+ if (fd < 0)
+ FAIL_EXIT1 ("mkstemp (\"%s\"): %m", temppath);
+ xunlink (temppath);
+ free (temppath);
+ }
+
+ /* Make sure that there is backing storage, so that the fill
+ operation will not fault. */
+ if (posix_fallocate (fd, 0, stride_size) != 0)
+ FAIL_EXIT1 ("posix_fallocate (%zu): %m", stride_size);
+
+ /* The stride size must still be a multiple of the page size and
+ element size. */
+ TEST_VERIFY_EXIT ((stride_size % page_size) == 0);
+ TEST_VERIFY_EXIT ((stride_size % element_size) == 0);
+
+ /* Fill the backing store. */
+ {
+ void *ptr = mmap (target, stride_size, PROT_READ | PROT_WRITE,
+ MAP_FIXED | MAP_FILE | MAP_SHARED, fd, 0);
+ if (ptr == MAP_FAILED)
+ {
+ int saved_errno = errno;
+ xmunmap (target, total_size);
+ xclose (fd);
+ errno = saved_errno;
+ return (struct support_blob_repeat) { 0 };
+ }
+ if (ptr != target)
+ FAIL_EXIT1 ("mapping of %zu bytes moved from %p to %p",
+ stride_size, target, ptr);
+
+ /* Write the repeating data. */
+ fill (target, element, element_size, stride_size / element_size);
+
+ /* Return to a PROT_NONE mapping, just to be on the safe side. */
+ ptr = mmap (target, stride_size, PROT_NONE,
+ MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+ if (ptr == MAP_FAILED)
+ FAIL_EXIT1 ("Failed to reinstate PROT_NONE mapping: %m");
+ if (ptr != target)
+ FAIL_EXIT1 ("PROT_NONE mapping of %zu bytes moved from %p to %p",
+ stride_size, target, ptr);
+ }
+
+ /* Create the alias mappings. */
+ {
+ size_t remaining_size = total_size;
+ char *current = target;
+ int flags = MAP_FIXED | MAP_FILE | MAP_PRIVATE;
+#ifdef MAP_NORESERVE
+ flags |= MAP_NORESERVE;
+#endif
+ while (remaining_size > 0)
+ {
+ size_t to_map = stride_size;
+ if (to_map > remaining_size)
+ to_map = remaining_size;
+ void *ptr = mmap (current, to_map, PROT_READ | PROT_WRITE,
+ flags, fd, 0);
+ if (ptr == MAP_FAILED)
+ {
+ int saved_errno = errno;
+ xmunmap (target, total_size);
+ xclose (fd);
+ errno = saved_errno;
+ return (struct support_blob_repeat) { 0 };
+ }
+ if (ptr != current)
+ FAIL_EXIT1 ("MAP_PRIVATE mapping of %zu bytes moved from %p to %p",
+ to_map, target, ptr);
+ remaining_size -= to_map;
+ current += to_map;
+ }
+ }
+
+ xclose (fd);
+
+ return (struct support_blob_repeat)
+ {
+ .start = target,
+ .size = total_size,
+ .use_malloc = false
+ };
+}
+
+struct support_blob_repeat
+support_blob_repeat_allocate (const void *element, size_t element_size,
+ size_t count)
+{
+ size_t total_size;
+ if (__builtin_mul_overflow (element_size, count, &total_size))
+ {
+ errno = EOVERFLOW;
+ return (struct support_blob_repeat) { 0 };
+ }
+ if (total_size <= maximum_small_size)
+ return allocate_malloc (total_size, element, element_size, count);
+ else
+ return allocate_big (total_size, element, element_size, count);
+}
+
+void
+support_blob_repeat_free (struct support_blob_repeat *blob)
+{
+ if (blob->size > 0)
+ {
+ int saved_errno = errno;
+ if (blob->use_malloc)
+ free (blob->start);
+ else
+ xmunmap (blob->start, blob->size);
+ errno = saved_errno;
+ }
+ *blob = (struct support_blob_repeat) { 0 };
+}
--- /dev/null
+/* Repeating a memory blob, with alias mapping optimization.
+ Copyright (C) 2018 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef SUPPORT_BLOB_REPEAT_H
+#define SUPPORT_BLOB_REPEAT_H
+
+#include <stdbool.h>
+#include <stddef.h>
+
+struct support_blob_repeat
+{
+ void *start;
+ size_t size;
+ bool use_malloc;
+};
+
+/* Return an allocation of COUNT elements, each of ELEMENT_SIZE bytes,
+ initialized with the bytes starting at ELEMENT. The memory is
+ writable (and thus counts towards the commit charge). In case of
+ on error, all members of the return struct are zero-initialized,
+ and errno is set accordingly. */
+struct support_blob_repeat support_blob_repeat_allocate (const void *element,
+ size_t element_size,
+ size_t count);
+
+/* Deallocate the blob created by support_blob_repeat_allocate. */
+void support_blob_repeat_free (struct support_blob_repeat *);
+
+#endif /* SUPPORT_BLOB_REPEAT_H */
#include <string.h>
#include <sys/param.h>
#include <sys/resource.h>
+#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
/* The cleanup handler passed to test_main. */
static void (*cleanup_function) (void);
+static void
+print_timestamp (const char *what, struct timeval tv)
+{
+ struct tm tm;
+ if (gmtime_r (&tv.tv_sec, &tm) == NULL)
+ printf ("%s: %lld.%06d\n",
+ what, (long long int) tv.tv_sec, (int) tv.tv_usec);
+ else
+ printf ("%s: %04d-%02d-%02dT%02d:%02d:%02d.%06d\n",
+ what, 1900 + tm.tm_year, tm.tm_mon + 1, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec, (int) tv.tv_usec);
+}
+
/* Timeout handler. We kill the child and exit with an error. */
static void
__attribute__ ((noreturn))
int killed;
int status;
+ /* Do this first to avoid further interference from the
+ subprocess. */
+ struct timeval now;
+ bool now_available = gettimeofday (&now, NULL) == 0;
+ struct stat64 st;
+ bool st_available = fstat64 (STDOUT_FILENO, &st) == 0 && st.st_mtime != 0;
+
assert (test_pid > 1);
/* Kill the whole process group. */
kill (-test_pid, SIGKILL);
printf ("Timed out: killed the child process but it exited %d\n",
WEXITSTATUS (status));
+ if (now_available)
+ print_timestamp ("Termination time", now);
+ if (st_available)
+ print_timestamp ("Last write to standard output",
+ (struct timeval) { st.st_mtim.tv_sec,
+ st.st_mtim.tv_nsec / 1000 });
+
/* Exit with an error. */
exit (1);
}
--- /dev/null
+/* Tests for <support/blob_repeat.h>
+ Copyright (C) 2018 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <support/blob_repeat.h>
+#include <support/check.h>
+
+static int
+do_test (void)
+{
+ struct support_blob_repeat repeat
+ = support_blob_repeat_allocate ("5", 1, 5);
+ TEST_COMPARE_BLOB (repeat.start, repeat.size, "55555", 5);
+ support_blob_repeat_free (&repeat);
+
+ repeat = support_blob_repeat_allocate ("ABC", 3, 3);
+ TEST_COMPARE_BLOB (repeat.start, repeat.size, "ABCABCABC", 9);
+ support_blob_repeat_free (&repeat);
+
+ repeat = support_blob_repeat_allocate ("abc", 4, 3);
+ TEST_COMPARE_BLOB (repeat.start, repeat.size, "abc\0abc\0abc", 12);
+ support_blob_repeat_free (&repeat);
+
+ size_t gigabyte = 1U << 30;
+ repeat = support_blob_repeat_allocate ("X", 1, gigabyte + 1);
+ if (repeat.start == NULL)
+ puts ("warning: not enough memory for 1 GiB mapping");
+ else
+ {
+ TEST_COMPARE (repeat.size, gigabyte + 1);
+ {
+ unsigned char *p = repeat.start;
+ for (size_t i = 0; i < gigabyte + 1; ++i)
+ if (p[i] != 'X')
+ FAIL_EXIT1 ("invalid byte 0x%02x at %zu", p[i], i);
+
+ /* Check that there is no sharing across the mapping. */
+ p[0] = 'Y';
+ p[1U << 24] = 'Z';
+ for (size_t i = 0; i < gigabyte + 1; ++i)
+ if (i == 0)
+ TEST_COMPARE (p[i], 'Y');
+ else if (i == 1U << 24)
+ TEST_COMPARE (p[i], 'Z');
+ else if (p[i] != 'X')
+ FAIL_EXIT1 ("invalid byte 0x%02x at %zu", p[i], i);
+ }
+ }
+ support_blob_repeat_free (&repeat);
+
+ repeat = support_blob_repeat_allocate ("012345678", 9, 10 * 1000 * 1000);
+ if (repeat.start == NULL)
+ puts ("warning: not enough memory for large mapping");
+ else
+ {
+ unsigned char *p = repeat.start;
+ for (int i = 0; i < 10 * 1000 * 1000; ++i)
+ for (int j = 0; j <= 8; ++j)
+ if (p[i * 9 + j] != '0' + j)
+ {
+ printf ("error: element %d index %d\n", i, j);
+ TEST_COMPARE (p[i * 9 + j], '0' + j);
+ }
+ }
+ support_blob_repeat_free (&repeat);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
*reloc_addr = value;
}
else
- __libc_fatal ("unexpected reloc type in static binary");
+ __libc_fatal ("Unexpected reloc type in static binary.\n");
}
#endif
*reloc_addr = value;
}
else
- __libc_fatal ("unexpected reloc type in static binary");
+ __libc_fatal ("Unexpected reloc type in static binary.\n");
}
#endif /* dl-irel.h */
struct frame_state_reg_info *old_rs = fs->regs.prev;
#ifdef _LIBC
if (old_rs == NULL)
- __libc_fatal ("invalid DWARF unwind data");
+ __libc_fatal ("Invalid DWARF unwind data.\n");
else
#endif
{
return self->thread_specifics[key];
}
strong_alias (__pthread_getspecific, pthread_getspecific);
+hidden_def (__pthread_getspecific)
return 0;
}
strong_alias (__pthread_setspecific, pthread_setspecific);
+hidden_def (__pthread_setspecific)
#if IS_IN (libpthread)
hidden_proto (__pthread_key_create)
+hidden_proto (__pthread_getspecific)
+hidden_proto (__pthread_setspecific)
hidden_proto (_pthread_mutex_init)
#endif
+++ /dev/null
-/* Linux/i386 CET initializers function.
- Copyright (C) 2018 Free Software Foundation, Inc.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, see
- <http://www.gnu.org/licenses/>. */
-
-
-#define LINKAGE static inline
-#define _dl_cet_check cet_check
-#include <sysdeps/x86/dl-cet.c>
-#undef _dl_cet_check
-
-#ifdef SHARED
-void
-_dl_cet_check (struct link_map *main_map, const char *program)
-{
- cet_check (main_map, program);
-
- if ((GL(dl_x86_feature_1)[0] & GNU_PROPERTY_X86_FEATURE_1_SHSTK))
- {
- /* Replace _dl_runtime_resolve and _dl_runtime_profile with
- _dl_runtime_resolve_shstk and _dl_runtime_profile_shstk,
- respectively if SHSTK is enabled. */
- extern void _dl_runtime_resolve (Elf32_Word) attribute_hidden;
- extern void _dl_runtime_resolve_shstk (Elf32_Word) attribute_hidden;
- extern void _dl_runtime_profile (Elf32_Word) attribute_hidden;
- extern void _dl_runtime_profile_shstk (Elf32_Word) attribute_hidden;
- unsigned int i;
- struct link_map *l;
- Elf32_Addr *got;
-
- if (main_map->l_info[DT_JMPREL])
- {
- got = (Elf32_Addr *) D_PTR (main_map, l_info[DT_PLTGOT]);
- if (got[2] == (Elf32_Addr) &_dl_runtime_resolve)
- got[2] = (Elf32_Addr) &_dl_runtime_resolve_shstk;
- else if (got[2] == (Elf32_Addr) &_dl_runtime_profile)
- got[2] = (Elf32_Addr) &_dl_runtime_profile_shstk;
- }
-
- i = main_map->l_searchlist.r_nlist;
- while (i-- > 0)
- {
- l = main_map->l_initfini[i];
- if (l->l_info[DT_JMPREL])
- {
- got = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
- if (got[2] == (Elf32_Addr) &_dl_runtime_resolve)
- got[2] = (Elf32_Addr) &_dl_runtime_resolve_shstk;
- else if (got[2] == (Elf32_Addr) &_dl_runtime_profile)
- got[2] = (Elf32_Addr) &_dl_runtime_profile_shstk;
- }
- }
- }
-}
-#endif
*reloc_addr = value;
}
else
- __libc_fatal ("unexpected reloc type in static binary");
+ __libc_fatal ("Unexpected reloc type in static binary.\n");
}
#endif /* dl-irel.h */
Elf32_Addr *got;
extern void _dl_runtime_resolve (Elf32_Word) attribute_hidden;
extern void _dl_runtime_profile (Elf32_Word) attribute_hidden;
+ extern void _dl_runtime_resolve_shstk (Elf32_Word) attribute_hidden;
+ extern void _dl_runtime_profile_shstk (Elf32_Word) attribute_hidden;
+ /* Check if SHSTK is enabled by kernel. */
+ bool shstk_enabled
+ = (GL(dl_x86_feature_1)[0] & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0;
if (l->l_info[DT_JMPREL] && lazy)
{
end in this function. */
if (__glibc_unlikely (profile))
{
- got[2] = (Elf32_Addr) &_dl_runtime_profile;
+ got[2] = (shstk_enabled
+ ? (Elf32_Addr) &_dl_runtime_profile_shstk
+ : (Elf32_Addr) &_dl_runtime_profile);
if (GLRO(dl_profile) != NULL
&& _dl_name_match_p (GLRO(dl_profile), l))
else
/* This function will get called to fix up the GOT entry indicated by
the offset on the stack, and then jump to the resolved address. */
- got[2] = (Elf32_Addr) &_dl_runtime_resolve;
+ got[2] = (shstk_enabled
+ ? (Elf32_Addr) &_dl_runtime_resolve_shstk
+ : (Elf32_Addr) &_dl_runtime_resolve);
}
return lazy;
NULL
*/
- .text
- .globl _start
- .type _start,@function
-_start:
+#include <sysdep.h>
+
+ENTRY (_start)
+ /* Clearing frame pointer is insufficient, use CFI. */
+ cfi_undefined (eip)
/* Clear the frame pointer. The ABI suggests this be done, to mark
the outermost frame obviously. */
xorl %ebp, %ebp
1: movl (%esp), %ebx
ret
#endif
+END (_start)
/* To fulfill the System V/i386 ABI we need this symbol. Yuck, it's so
meaningless since we don't support machines < 80386. */
.section .text
-GLOBAL_LIBM_ENTRY(__exp2f)
+WEAK_LIBM_ENTRY(exp2f)
{.mfi
}
;;
-GLOBAL_LIBM_END(__exp2f)
+WEAK_LIBM_END(exp2f)
libm_alias_float_other (__exp2, exp2)
#ifdef SHARED
-.symver __exp2f,exp2f@@GLIBC_2.27
+.symver exp2f,exp2f@@GLIBC_2.27
.weak __exp2f_compat
.set __exp2f_compat,__exp2f
.symver __exp2f_compat,exp2f@GLIBC_2.2
.section .text
-GLOBAL_LIBM_ENTRY(__log2f)
+WEAK_LIBM_ENTRY(log2f)
{ .mfi
alloc r32=ar.pfs,1,4,4,0
br.ret.sptk b0;;
}
-GLOBAL_LIBM_END(__log2f)
+WEAK_LIBM_END(log2f)
libm_alias_float_other (__log2, log2)
#ifdef SHARED
-.symver __log2f,log2f@@GLIBC_2.27
+.symver log2f,log2f@@GLIBC_2.27
.weak __log2f_compat
.set __log2f_compat,__log2f
.symver __log2f_compat,log2f@GLIBC_2.2
LOCAL_OBJECT_END(pow_tbl2)
.section .text
-GLOBAL_LIBM_ENTRY(__powf)
+WEAK_LIBM_ENTRY(powf)
// Get exponent of x. Will be used to calculate K.
{ .mfi
}
;;
-GLOBAL_LIBM_END(__powf)
+WEAK_LIBM_END(powf)
libm_alias_float_other (__pow, pow)
#ifdef SHARED
-.symver __powf,powf@@GLIBC_2.27
+.symver powf,powf@@GLIBC_2.27
.weak __powf_compat
.set __powf_compat,__powf
.symver __powf_compat,powf@GLIBC_2.2
unsigned int __nusers;
#endif
/* KIND must stay at this position in the structure to maintain
- binary compatibility with static initializers. */
+ binary compatibility with static initializers.
+
+ Concurrency notes:
+ The __kind of a mutex is initialized either by the static
+ PTHREAD_MUTEX_INITIALIZER or by a call to pthread_mutex_init.
+
+ After a mutex has been initialized, the __kind of a mutex is usually not
+ changed. BUT it can be set to -1 in pthread_mutex_destroy or elision can
+ be enabled. This is done concurrently in the pthread_mutex_*lock functions
+ by using the macro FORCE_ELISION. This macro is only defined for
+ architectures which supports lock elision.
+
+ For elision, there are the flags PTHREAD_MUTEX_ELISION_NP and
+ PTHREAD_MUTEX_NO_ELISION_NP which can be set in addition to the already set
+ type of a mutex.
+ Before a mutex is initialized, only PTHREAD_MUTEX_NO_ELISION_NP can be set
+ with pthread_mutexattr_settype.
+ After a mutex has been initialized, the functions pthread_mutex_*lock can
+ enable elision - if the mutex-type and the machine supports it - by setting
+ the flag PTHREAD_MUTEX_ELISION_NP. This is done concurrently. Afterwards
+ the lock / unlock functions are using specific elision code-paths. */
int __kind;
__PTHREAD_COMPAT_PADDING_MID
#if __PTHREAD_MUTEX_NUSERS_AFTER_KIND
static __always_inline __attribute__ ((__noreturn__)) void
futex_fatal_error (void)
{
- __libc_fatal ("The futex facility returned an unexpected error code.");
+ __libc_fatal ("The futex facility returned an unexpected error code.\n");
}
#endif /* futex-internal.h */
*reloc_addr = value;
}
else
- __libc_fatal ("unexpected reloc type in static binary");
+ __libc_fatal ("Unexpected reloc type in static binary.\n");
}
#endif /* dl-irel.h */
#endif
}
else
- __libc_fatal ("unexpected reloc type in static binary");
+ __libc_fatal ("Unexpected reloc type in static binary.\n");
}
#endif /* dl-irel.h */
ldouble: 2
Function: "cos":
+double: 1
+idouble: 1
ildouble: 1
ldouble: 1
ldouble: 4
Function: Imaginary part of "ctan_towardzero":
-double: 1
+double: 2
float: 2
-idouble: 1
+idouble: 2
ifloat: 2
ildouble: 5
ldouble: 5
Function: "log_upward":
double: 1
idouble: 1
-ildouble: 1
-ldouble: 1
+ildouble: 2
+ldouble: 2
Function: "pow":
+double: 1
+idouble: 1
ildouble: 2
ldouble: 2
ldouble: 2
Function: "sin":
+double: 1
+idouble: 1
ildouble: 1
ldouble: 1
ldouble: 3
Function: "sincos":
+double: 1
+idouble: 1
ildouble: 1
ldouble: 1
static __always_inline void
libc_feholdexcept_setround_riscv (fenv_t *envp, int round)
{
- libc_fesetround_riscv (round);
libc_feholdexcept_riscv (envp);
+ libc_fesetround_riscv (round);
}
#define libc_feholdexcept_setround libc_feholdexcept_setround_riscv
*reloc_addr = value;
}
else
- __libc_fatal ("unexpected reloc type in static binary");
+ __libc_fatal ("Unexpected reloc type in static binary.\n");
}
#endif /* dl-irel.h */
else if (r_type == R_SPARC_NONE)
;
else
- __libc_fatal ("unexpected reloc type in static binary");
+ __libc_fatal ("Unexpected reloc type in static binary.\n");
}
#endif /* dl-irel.h */
else if (r_type == R_SPARC_NONE)
;
else
- __libc_fatal ("unexpected reloc type in static binary");
+ __libc_fatal ("Unexpected reloc type in static binary.\n");
}
#endif /* dl-irel.h */
ifeq ($(subdir),dirent)
sysdep_routines += getdirentries getdirentries64
+tests-internal += tst-readdir64-compat
endif
ifeq ($(subdir),nis)
/* SIGPOLL. */
struct
{
- long int si_band; /* Band event for SIGPOLL. */
+ __SI_BAND_TYPE si_band; /* Band event for SIGPOLL. */
int si_fd;
} _sigpoll;
# include <shlib-compat.h>
# if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2)
-# include <olddirent.h>
+# include <olddirent.h>
+# include <unistd.h>
-/* kernel definition of as of 3.2. */
-struct compat_linux_dirent
+static ssize_t
+handle_overflow (int fd, __off64_t offset, ssize_t count)
{
- /* Both d_ino and d_off are compat_ulong_t which are defined in all
- architectures as 'u32'. */
- uint32_t d_ino;
- uint32_t d_off;
- unsigned short d_reclen;
- char d_name[1];
-};
+ /* If this is the first entry in the buffer, we can report the
+ error. */
+ if (count == 0)
+ {
+ __set_errno (EOVERFLOW);
+ return -1;
+ }
+
+ /* Otherwise, seek to the overflowing entry, so that the next call
+ will report the error, and return the data read so far.. */
+ if (__lseek64 (fd, offset, SEEK_SET) != 0)
+ return -1;
+ return count;
+}
ssize_t
__old_getdents64 (int fd, char *buf, size_t nbytes)
{
- ssize_t retval = INLINE_SYSCALL_CALL (getdents, fd, buf, nbytes);
+ /* We do not move the individual directory entries. This is only
+ possible if the target type (struct __old_dirent64) is smaller
+ than the source type. */
+ _Static_assert (offsetof (struct __old_dirent64, d_name)
+ <= offsetof (struct dirent64, d_name),
+ "__old_dirent64 is larger than dirent64");
+ _Static_assert (__alignof__ (struct __old_dirent64)
+ <= __alignof__ (struct dirent64),
+ "alignment of __old_dirent64 is larger than dirent64");
- /* The kernel added the d_type value after the name. Change this now. */
- if (retval != -1)
+ ssize_t retval = INLINE_SYSCALL_CALL (getdents64, fd, buf, nbytes);
+ if (retval > 0)
{
- union
- {
- struct compat_linux_dirent k;
- struct dirent u;
- } *kbuf = (void *) buf;
-
- while ((char *) kbuf < buf + retval)
+ char *p = buf;
+ char *end = buf + retval;
+ while (p < end)
{
- char d_type = *((char *) kbuf + kbuf->k.d_reclen - 1);
- memmove (kbuf->u.d_name, kbuf->k.d_name,
- strlen (kbuf->k.d_name) + 1);
- kbuf->u.d_type = d_type;
+ struct dirent64 *source = (struct dirent64 *) p;
+
+ /* Copy out the fixed-size data. */
+ __ino_t ino = source->d_ino;
+ __off64_t offset = source->d_off;
+ unsigned int reclen = source->d_reclen;
+ unsigned char type = source->d_type;
+
+ /* Check for ino_t overflow. */
+ if (__glibc_unlikely (ino != source->d_ino))
+ return handle_overflow (fd, offset, p - buf);
+
+ /* Convert to the target layout. Use a separate struct and
+ memcpy to side-step aliasing issues. */
+ struct __old_dirent64 result;
+ result.d_ino = ino;
+ result.d_off = offset;
+ result.d_reclen = reclen;
+ result.d_type = type;
+
+ /* Write the fixed-sized part of the result to the
+ buffer. */
+ size_t result_name_offset = offsetof (struct __old_dirent64, d_name);
+ memcpy (p, &result, result_name_offset);
+
+ /* Adjust the position of the name if necessary. Copy
+ everything until the end of the record, including the
+ terminating NUL byte. */
+ if (result_name_offset != offsetof (struct dirent64, d_name))
+ memmove (p + result_name_offset, source->d_name,
+ reclen - offsetof (struct dirent64, d_name));
- kbuf = (void *) ((char *) kbuf + kbuf->k.d_reclen);
+ p += reclen;
}
}
return retval;
{
int ret = __gethostbyname_r (hostname, &hostbuf,
tmpbuf.data, tmpbuf.length, &hp, &herr);
- if (ret == 0)
+ if (ret == 0 && hp != NULL)
break;
else
{
/* Enlarge the buffer on ERANGE. */
- if (herr == NETDB_INTERNAL && errno == ERANGE)
+ if (ret != 0 && herr == NETDB_INTERNAL && errno == ERANGE)
{
if (!scratch_buffer_grow (&tmpbuf))
return 0;
return 0;
#else
struct ifreq ifr;
- int fd = __opensock ();
-
- if (fd < 0)
- return 0;
-
if (strlen (ifname) >= IFNAMSIZ)
{
__set_errno (ENODEV);
}
strncpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+
+ int fd = __opensock ();
+
+ if (fd < 0)
+ return 0;
+
if (__ioctl (fd, SIOCGIFINDEX, &ifr) < 0)
{
int saved_errno = errno;
char message[200];
if (family < 0)
__snprintf (message, sizeof (message),
- "Unexpected error %d on netlink descriptor %d",
+ "Unexpected error %d on netlink descriptor %d.\n",
error_code, fd);
else
__snprintf (message, sizeof (message),
"Unexpected error %d on netlink descriptor %d"
- " (address family %d)",
+ " (address family %d).\n",
error_code, fd, family);
__libc_fatal (message);
}
/* Automatically enable elision for existing user lock kinds. */
#define FORCE_ELISION(m, s) \
- if (__pthread_force_elision \
- && (m->__data.__kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0) \
+ if (__pthread_force_elision) \
{ \
- mutex->__data.__kind |= PTHREAD_MUTEX_ELISION_NP; \
- s; \
+ /* See concurrency notes regarding __kind in \
+ struct __pthread_mutex_s in \
+ sysdeps/nptl/bits/thread-shared-types.h. \
+ \
+ There are the following cases for the kind of a mutex \
+ (The mask PTHREAD_MUTEX_ELISION_FLAGS_NP covers the flags \
+ PTHREAD_MUTEX_ELISION_NP and PTHREAD_MUTEX_NO_ELISION_NP where \
+ only one of both flags can be set): \
+ - both flags are not set: \
+ This is the first lock operation for this mutex. Enable \
+ elision as it is not enabled so far. \
+ Note: It can happen that multiple threads are calling e.g. \
+ pthread_mutex_lock at the same time as the first lock \
+ operation for this mutex. Then elision is enabled for this \
+ mutex by multiple threads. Storing with relaxed MO is enough \
+ as all threads will store the same new value for the kind of \
+ the mutex. But we have to ensure that we always use the \
+ elision path regardless if this thread has enabled elision or \
+ another one. \
+ \
+ - PTHREAD_MUTEX_ELISION_NP flag is set: \
+ Elision was already enabled for this mutex by a previous lock \
+ operation. See case above. Just use the elision path. \
+ \
+ - PTHREAD_MUTEX_NO_ELISION_NP flag is set: \
+ Elision was explicitly disabled by pthread_mutexattr_settype. \
+ Do not use the elision path. \
+ Note: The flag PTHREAD_MUTEX_NO_ELISION_NP will never be \
+ changed after mutex initialization. */ \
+ int mutex_kind = atomic_load_relaxed (&((m)->__data.__kind)); \
+ if ((mutex_kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0) \
+ { \
+ mutex_kind |= PTHREAD_MUTEX_ELISION_NP; \
+ atomic_store_relaxed (&((m)->__data.__kind), mutex_kind); \
+ } \
+ if ((mutex_kind & PTHREAD_MUTEX_ELISION_NP) != 0) \
+ { \
+ s; \
+ } \
}
# ifdef __NR_preadv2
ssize_t result = SYSCALL_CANCEL (preadv2, fd, vector, count,
LO_HI_LONG (offset), flags);
- if (result >= 0)
+ if (result >= 0 || errno != ENOSYS)
return result;
# endif
/* Trying to emulate the preadv2 syscall flags is troublesome:
#ifdef __NR_preadv64v2
ssize_t result = SYSCALL_CANCEL (preadv64v2, fd, vector, count,
LO_HI_LONG (offset), flags);
- if (result >= 0)
+ if (result >= 0 || errno != ENOSYS)
return result;
#endif
/* Trying to emulate the preadv2 syscall flags is troublesome:
# ifdef __NR_pwritev2
ssize_t result = SYSCALL_CANCEL (pwritev2, fd, vector, count,
LO_HI_LONG (offset), flags);
- if (result >= 0)
+ if (result >= 0 || errno != ENOSYS)
return result;
# endif
/* Trying to emulate the pwritev2 syscall flags is troublesome:
#ifdef __NR_pwritev64v2
ssize_t result = SYSCALL_CANCEL (pwritev64v2, fd, vector, count,
LO_HI_LONG (offset), flags);
- if (result >= 0)
+ if (result >= 0 || errno != ENOSYS)
return result;
#endif
/* Trying to emulate the pwritev2 syscall flags is troublesome:
/* Automatically enable elision for existing user lock kinds. */
#define FORCE_ELISION(m, s) \
- if (__pthread_force_elision \
- && (m->__data.__kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0) \
+ if (__pthread_force_elision) \
{ \
- mutex->__data.__kind |= PTHREAD_MUTEX_ELISION_NP; \
- s; \
+ /* See concurrency notes regarding __kind in \
+ struct __pthread_mutex_s in \
+ sysdeps/nptl/bits/thread-shared-types.h. \
+ \
+ There are the following cases for the kind of a mutex \
+ (The mask PTHREAD_MUTEX_ELISION_FLAGS_NP covers the flags \
+ PTHREAD_MUTEX_ELISION_NP and PTHREAD_MUTEX_NO_ELISION_NP where \
+ only one of both flags can be set): \
+ - both flags are not set: \
+ This is the first lock operation for this mutex. Enable \
+ elision as it is not enabled so far. \
+ Note: It can happen that multiple threads are calling e.g. \
+ pthread_mutex_lock at the same time as the first lock \
+ operation for this mutex. Then elision is enabled for this \
+ mutex by multiple threads. Storing with relaxed MO is enough \
+ as all threads will store the same new value for the kind of \
+ the mutex. But we have to ensure that we always use the \
+ elision path regardless if this thread has enabled elision or \
+ another one. \
+ \
+ - PTHREAD_MUTEX_ELISION_NP flag is set: \
+ Elision was already enabled for this mutex by a previous lock \
+ operation. See case above. Just use the elision path. \
+ \
+ - PTHREAD_MUTEX_NO_ELISION_NP flag is set: \
+ Elision was explicitly disabled by pthread_mutexattr_settype. \
+ Do not use the elision path. \
+ Note: The flag PTHREAD_MUTEX_NO_ELISION_NP will never be \
+ changed after mutex initialization. */ \
+ int mutex_kind = atomic_load_relaxed (&((m)->__data.__kind)); \
+ if ((mutex_kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0) \
+ { \
+ mutex_kind |= PTHREAD_MUTEX_ELISION_NP; \
+ atomic_store_relaxed (&((m)->__data.__kind), mutex_kind); \
+ } \
+ if ((mutex_kind & PTHREAD_MUTEX_ELISION_NP) != 0) \
+ { \
+ s; \
+ } \
}
#ifndef _BITS_SIGINFO_ARCH_H
#define _BITS_SIGINFO_ARCH_H 1
-#define __SI_BAND_TYPE int
+/* The kernel uses int instead of long int (as in POSIX). In 32-bit
+ mode, we can still use long int, but in 64-bit mode, we need to
+ deviate from POSIX. */
+#if __WORDSIZE == 64
+# define __SI_BAND_TYPE int
+#endif
#define __SI_SIGFAULT_ADDL \
int _si_trapno;
ifeq ($(subdir),stdlib)
sysdep_routines += __start_context
endif
+
+ifeq ($(subdir),conform)
+# For bug 23821 (incorrect type of si_band).
+conformtest-xfail-conds += sparc64-linux
+endif
ptrdiff_t argc = args->argc;
/* Construct an argument list for the shell. */
- char *new_argv[argc + 1];
+ char *new_argv[argc + 2];
new_argv[0] = (char *) _PATH_BSHELL;
new_argv[1] = (char *) args->file;
if (argc > 1)
# names are only used if the installed kernel headers also provide
# them.
-# The list of system calls is current as of Linux 4.17.
-kernel 4.17
+# The list of system calls is current as of Linux 4.19.
+kernel 4.19
FAST_atomic_update
FAST_cmpxchg
io_cancel
io_destroy
io_getevents
+io_pgetevents
io_setup
io_submit
ioctl
request_key
restart_syscall
rmdir
+rseq
rt_sigaction
rt_sigpending
rt_sigprocmask
--- /dev/null
+/* Test readdir64 compatibility symbol.
+ Copyright (C) 2018 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <dirent.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <shlib-compat.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <support/check.h>
+
+/* Copied from <olddirent.h>. */
+struct __old_dirent64
+ {
+ __ino_t d_ino;
+ __off64_t d_off;
+ unsigned short int d_reclen;
+ unsigned char d_type;
+ char d_name[256];
+ };
+
+typedef struct __old_dirent64 *(*compat_readdir64_type) (DIR *);
+
+#if TEST_COMPAT (libc, GLIBC_2_1, GLIBC_2_2)
+struct __old_dirent64 *compat_readdir64 (DIR *);
+compat_symbol_reference (libc, compat_readdir64, readdir64, GLIBC_2_1);
+#endif
+
+static int
+do_test (void)
+{
+#if TEST_COMPAT (libc, GLIBC_2_1, GLIBC_2_2)
+
+ /* Directory stream using the non-compat readdir64 symbol. The test
+ checks against this. */
+ DIR *dir_reference = opendir (".");
+ TEST_VERIFY_EXIT (dir_reference != NULL);
+ DIR *dir_test = opendir (".");
+ TEST_VERIFY_EXIT (dir_test != NULL);
+
+ /* This loop assumes that the enumeration order is consistent for
+ two different handles. Nothing should write to the current
+ directory (in the source tree) while this test runs, so there
+ should not be any difference due to races. */
+ size_t count = 0;
+ while (true)
+ {
+ errno = 0;
+ struct dirent64 *entry_reference = readdir64 (dir_reference);
+ if (entry_reference == NULL && errno != 0)
+ FAIL_EXIT1 ("readdir64 entry %zu: %m\n", count);
+ struct __old_dirent64 *entry_test = compat_readdir64 (dir_test);
+ if (entry_reference == NULL)
+ {
+ if (errno == EOVERFLOW)
+ {
+ TEST_VERIFY (entry_reference->d_ino
+ != (__ino_t) entry_reference->d_ino);
+ printf ("info: inode number overflow at entry %zu\n", count);
+ break;
+ }
+ if (errno != 0)
+ FAIL_EXIT1 ("compat readdir64 entry %zu: %m\n", count);
+ }
+
+ /* Check that both streams end at the same time. */
+ if (entry_reference == NULL)
+ {
+ TEST_VERIFY (entry_test == NULL);
+ break;
+ }
+ else
+ TEST_VERIFY_EXIT (entry_test != NULL);
+
+ /* Check that the entries are the same. */
+ TEST_COMPARE_BLOB (entry_reference->d_name,
+ strlen (entry_reference->d_name),
+ entry_test->d_name, strlen (entry_test->d_name));
+ TEST_COMPARE (entry_reference->d_ino, entry_test->d_ino);
+ TEST_COMPARE (entry_reference->d_off, entry_test->d_off);
+ TEST_COMPARE (entry_reference->d_type, entry_test->d_type);
+ TEST_COMPARE (entry_reference->d_reclen, entry_test->d_reclen);
+
+ ++count;
+ }
+ printf ("info: %zu directory entries found\n", count);
+ TEST_VERIFY (count >= 3); /* ".", "..", and some source files. */
+
+ TEST_COMPARE (closedir (dir_test), 0);
+ TEST_COMPARE (closedir (dir_reference), 0);
+#endif
+ return 0;
+}
+
+#include <support/test-driver.c>
/* Automatically enable elision for existing user lock kinds. */
#define FORCE_ELISION(m, s) \
- if (__pthread_force_elision \
- && (m->__data.__kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0) \
+ if (__pthread_force_elision) \
{ \
- mutex->__data.__kind |= PTHREAD_MUTEX_ELISION_NP; \
- s; \
+ /* See concurrency notes regarding __kind in \
+ struct __pthread_mutex_s in \
+ sysdeps/nptl/bits/thread-shared-types.h. \
+ \
+ There are the following cases for the kind of a mutex \
+ (The mask PTHREAD_MUTEX_ELISION_FLAGS_NP covers the flags \
+ PTHREAD_MUTEX_ELISION_NP and PTHREAD_MUTEX_NO_ELISION_NP where \
+ only one of both flags can be set): \
+ - both flags are not set: \
+ This is the first lock operation for this mutex. Enable \
+ elision as it is not enabled so far. \
+ Note: It can happen that multiple threads are calling e.g. \
+ pthread_mutex_lock at the same time as the first lock \
+ operation for this mutex. Then elision is enabled for this \
+ mutex by multiple threads. Storing with relaxed MO is enough \
+ as all threads will store the same new value for the kind of \
+ the mutex. But we have to ensure that we always use the \
+ elision path regardless if this thread has enabled elision or \
+ another one. \
+ \
+ - PTHREAD_MUTEX_ELISION_NP flag is set: \
+ Elision was already enabled for this mutex by a previous lock \
+ operation. See case above. Just use the elision path. \
+ \
+ - PTHREAD_MUTEX_NO_ELISION_NP flag is set: \
+ Elision was explicitly disabled by pthread_mutexattr_settype. \
+ Do not use the elision path. \
+ Note: The flag PTHREAD_MUTEX_NO_ELISION_NP will never be \
+ changed after mutex initialization. */ \
+ int mutex_kind = atomic_load_relaxed (&((m)->__data.__kind)); \
+ if ((mutex_kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0) \
+ { \
+ mutex_kind |= PTHREAD_MUTEX_ELISION_NP; \
+ atomic_store_relaxed (&((m)->__data.__kind), mutex_kind); \
+ } \
+ if ((mutex_kind & PTHREAD_MUTEX_ELISION_NP) != 0) \
+ { \
+ s; \
+ } \
}
| bit_arch_Fast_Unaligned_Copy
| bit_arch_Prefer_PMINUB_for_stringop);
break;
+ }
+ /* Disable TSX on some Haswell processors to avoid TSX on kernels that
+ weren't updated with the latest microcode package (which disables
+ broken feature by default). */
+ switch (model)
+ {
case 0x3f:
/* Xeon E7 v3 with stepping >= 4 has working TSX. */
if (stepping >= 4)
const ElfW(Addr) align)
{
#if CET_ENABLED
+ /* Skip if we have seen a NT_GNU_PROPERTY_TYPE_0 note before. */
+ if (l->l_cet != lc_unknown)
+ return;
+
/* The NT_GNU_PROPERTY_TYPE_0 note must be aliged to 4 bytes in
32-bit objects and to 8 bytes in 64-bit objects. Skip notes
with incorrect alignment. */
const ElfW(Addr) start = (ElfW(Addr)) note;
+ unsigned int feature_1 = 0;
+ unsigned int last_type = 0;
+
while ((ElfW(Addr)) (note + 1) - start < size)
{
/* Find the NT_GNU_PROPERTY_TYPE_0 note. */
&& note->n_type == NT_GNU_PROPERTY_TYPE_0
&& memcmp (note + 1, "GNU", 4) == 0)
{
+ /* Stop if we see more than one GNU property note which may
+ be generated by the older linker. */
+ if (l->l_cet != lc_unknown)
+ return;
+
+ /* Check CET status now. */
+ l->l_cet = lc_none;
+
/* Check for invalid property. */
if (note->n_descsz < 8
|| (note->n_descsz % sizeof (ElfW(Addr))) != 0)
- break;
+ return;
/* Start and end of property array. */
unsigned char *ptr = (unsigned char *) (note + 1) + 4;
unsigned int type = *(unsigned int *) ptr;
unsigned int datasz = *(unsigned int *) (ptr + 4);
+ /* Property type must be in ascending order. */
+ if (type < last_type)
+ return;
+
ptr += 8;
if ((ptr + datasz) > ptr_end)
- break;
+ return;
+
+ last_type = type;
if (type == GNU_PROPERTY_X86_FEATURE_1_AND)
{
we stop the search regardless if its size is correct
or not. There is no point to continue if this note
is ill-formed. */
- if (datasz == 4)
- {
- unsigned int feature_1 = *(unsigned int *) ptr;
- if ((feature_1 & GNU_PROPERTY_X86_FEATURE_1_IBT))
- l->l_cet |= lc_ibt;
- if ((feature_1 & GNU_PROPERTY_X86_FEATURE_1_SHSTK))
- l->l_cet |= lc_shstk;
- }
+ if (datasz != 4)
+ return;
+
+ feature_1 = *(unsigned int *) ptr;
+
+ /* Keep searching for the next GNU property note
+ generated by the older linker. */
+ break;
+ }
+ else if (type > GNU_PROPERTY_X86_FEATURE_1_AND)
+ {
+ /* Stop since property type is in ascending order. */
return;
}
+ ELF_NOTE_NEXT_OFFSET (note->n_namesz, note->n_descsz,
align));
}
+
+ /* We get here only if there is one or no GNU property note. */
+ if ((feature_1 & GNU_PROPERTY_X86_FEATURE_1_IBT))
+ l->l_cet |= lc_ibt;
+ if ((feature_1 & GNU_PROPERTY_X86_FEATURE_1_SHSTK))
+ l->l_cet |= lc_shstk;
#endif
}
/* If this object is enabled with CET. */
enum
{
- lc_none = 0, /* Not enabled with CET. */
- lc_ibt = 1 << 0, /* Enabled with IBT. */
- lc_shstk = 1 << 1, /* Enabled with STSHK. */
+ lc_unknown = 0, /* Unknown CET status. */
+ lc_none = 1 << 0, /* Not enabled with CET. */
+ lc_ibt = 1 << 1, /* Enabled with IBT. */
+ lc_shstk = 1 << 2, /* Enabled with STSHK. */
lc_ibt_and_shstk = lc_ibt | lc_shstk /* Enabled with both. */
- } l_cet:2;
+ } l_cet:3;
*reloc_addr = value;
}
else
- __libc_fatal ("unexpected reloc type in static binary");
+ __libc_fatal ("Unexpected reloc type in static binary.\n");
}
#endif /* dl-irel.h */
/* First "register" all timezone names. */
for (i = 0; i < num_types; ++i)
- (void) __tzstring (&zone_names[types[i].idx]);
+ if (__tzstring (&zone_names[types[i].idx]) == NULL)
+ goto ret_free_transitions;
/* Find the standard and daylight time offsets used by the rule file.
We choose the offsets in the types of each flavor that are