mirror of
git://sourceware.org/git/glibc.git
synced 2026-09-09 11:58:23 +08:00
Compare commits
53
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a67ffcfae3 | ||
|
|
136c42bf12 | ||
|
|
43765a182c | ||
|
|
1b248392fb | ||
|
|
cf161d3911 | ||
|
|
a274119b0e | ||
|
|
a18c25e0ee | ||
|
|
124ea50584 | ||
|
|
5a8692a646 | ||
|
|
6a277a415c | ||
|
|
9e1e8f68d5 | ||
|
|
dd08634b37 | ||
|
|
749c94d44c | ||
|
|
b533edfeed | ||
|
|
4b31bd831a | ||
|
|
50992336ac | ||
|
|
39ad1d1244 | ||
|
|
7f2efd6c26 | ||
|
|
a68cafa11c | ||
|
|
6e5cb616b5 | ||
|
|
02b2a80526 | ||
|
|
9ac61c0047 | ||
|
|
59c0f6ff86 | ||
|
|
94dc51ad84 | ||
|
|
50d2d4bb0e | ||
|
|
3a6219d3ec | ||
|
|
f5eb5f9c91 | ||
|
|
3b7f56026c | ||
|
|
daf161ce63 | ||
|
|
87efefb037 | ||
|
|
65c7020d26 | ||
|
|
9f95ec0adb | ||
|
|
1885fe873e | ||
|
|
16d0a0ce76 | ||
|
|
014eaa2207 | ||
|
|
965630aefa | ||
|
|
51e762570e | ||
|
|
163437ec37 | ||
|
|
f676ce661c | ||
|
|
907cc11c57 | ||
|
|
dbcaca73cb | ||
|
|
26f36461f6 | ||
|
|
e04da210f7 | ||
|
|
e871e19b5f | ||
|
|
f2cdbadd8a | ||
|
|
978908245b | ||
|
|
8a4e5cc657 | ||
|
|
fe7b1136e5 | ||
|
|
d679497db2 | ||
|
|
01b07c70ad | ||
|
|
75adf430d2 | ||
|
|
c66e8b9e58 | ||
|
|
004c993bdd |
@@ -1,3 +1,600 @@
|
||||
2017-04-21 Joseph Myers <joseph@codesourcery.com>
|
||||
|
||||
* io/ftwtest-sh: Also trap on exit to remove temporary files.
|
||||
|
||||
2017-04-11 Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
* posix/globtest.sh: Add cleanup routine on trap 0.
|
||||
|
||||
2017-02-07 Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
* malloc/arena.c (__malloc_fork_lock_parent): Add internal_function
|
||||
attribute.
|
||||
(__malloc_fork_unlock_parent): Likewise.
|
||||
(__malloc_fork_unlock_child): Likewise.
|
||||
|
||||
2015-07-29 H.J. Lu <hongjiu.lu@intel.com>
|
||||
|
||||
[BZ #18078]
|
||||
* scripts/check-localplt.awk: Support alternate relocations.
|
||||
* scripts/localplt.awk: Also check relocations in DT_RELA/DT_REL
|
||||
sections.
|
||||
* sysdeps/unix/sysv/linux/i386/localplt.data: Mark free and
|
||||
malloc entries with + REL R_386_GLOB_DAT.
|
||||
* sysdeps/x86_64/localplt.data: New file.
|
||||
|
||||
2015-03-03 Alan Modra <amodra@gmail.com>
|
||||
|
||||
[BZ #16512]
|
||||
* scripts/localplt.awk: Strip off symbol version.
|
||||
* NEWS: Mention bug fix.
|
||||
|
||||
2016-08-26 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
[BZ #20432]
|
||||
Avoid strong references to malloc-internal symbols when linking
|
||||
statically, to support statically interposed mallocs.
|
||||
* include/libc-symbols.h (call_function_static_weak): New macro.
|
||||
* malloc/Makefile (tests): Add tst-interpose-nothread,
|
||||
tst-interpose-thread, tst-interpose-static-nothread,
|
||||
tst-interpose-static-thread.
|
||||
(tests-static): Add tst-interpose-static-nothread,
|
||||
tst-interpose-static-thread.
|
||||
(extra-tests-objs): Add tst-interpose-aux-nothread.o,
|
||||
tst-interpose-aux-thread.o.
|
||||
(test-extras): Add tst-interpose-aux-nothread,
|
||||
tst-interpose-aux-thread.
|
||||
(tst-interpose-nothread, tst-interpose-static-nothread): Link with
|
||||
tst-interpose-aux-nothread.o.
|
||||
(tst-interpose-thread, tst-interpose-static-thread): Link with
|
||||
tst-interpose-aux-thread.o and libthread.
|
||||
* malloc/tst-interpose-aux-nothread.c: New file.
|
||||
* malloc/tst-interpose-aux-thread.c: Likewise.
|
||||
* malloc/tst-interpose-aux.c: Likewise.
|
||||
* malloc/tst-interpose-aux.h: Likewise.
|
||||
* malloc/tst-interpose-nothread.c: Likewise.
|
||||
* malloc/tst-interpose-skeleton.c: Likewise.
|
||||
* malloc/tst-interpose-static-nothread.c: Likewise.
|
||||
* malloc/tst-interpose-static-thread.c: Likewise.
|
||||
* malloc/tst-interpose-thread.c: Likewise.
|
||||
* nptl/tst-tls3-malloc.c: Use new interposed malloc.
|
||||
* sysdeps/mach/hurd/fork.c (__fork): Only call
|
||||
__malloc_fork_lock_parent, __malloc_fork_unlock_parent,
|
||||
__malloc_fork_unlock_child if defined.
|
||||
* sysdeps/nptl/fork.c (__libc_fork): Likewise.
|
||||
|
||||
2016-08-16 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
* nptl/tst-tls3.c (default_stack_size_in_mb, stack_size_in_mb):
|
||||
New.
|
||||
(do_test): Apply default_stack_size_in_mb if not set.
|
||||
* nptl/tst-tls3-malloc.c (stack_size_in_mb): Override default.
|
||||
|
||||
2016-08-02 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
[BZ #19469]
|
||||
* malloc/Makefile (CPPFLAGS): Compile tests with
|
||||
-DTEST_NO_MALLOPT.
|
||||
* test-skeleton.c (main): Only call mallopt if !TEST_NO_MALLOPT.
|
||||
|
||||
2016-08-03 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
[BZ #17730]
|
||||
Avoid using memalign for TCB allocations.
|
||||
* elf/dl-tls.c (tcb_to_pointer_to_free_location): New.
|
||||
(_dl_allocate_tls_storage): Use malloc and manual alignment.
|
||||
Avoid alignment gap in the TLS_DTV_AT_TP case.
|
||||
(_dl_deallocate_tls): Use tcb_to_pointer_to_free_location to
|
||||
determine the pointer to free.
|
||||
* nptl/tst-tls3-malloc.c: New test.
|
||||
* nptl/Makefile (tests): Add it.
|
||||
(tst-tls3-malloc): Link with libdl, libpthread.
|
||||
(LDFLAGS-tst-tls3-malloc): Set.
|
||||
(tst-tls3-malloc.out): Depend on DSO used in test.
|
||||
|
||||
2016-08-03 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
[BZ #17730]
|
||||
Avoid using memalign for TLS allocations.
|
||||
* sysdeps/generic/dl-dtv.h (struct dtv_pointer): New. Replaces
|
||||
is_static member with to_free member.
|
||||
(union dtv): Use struct dtv_pointer.
|
||||
* csu/libc-tls.c (__libc_setup_tls): Set to_free member of struct
|
||||
dtv_pointer instead of is_static.
|
||||
* elf/dl-tls.c (_dl_allocate_tls_init): Likewise.
|
||||
(_dl_deallocate_tls): Free to_free member of struct dtv_pointer
|
||||
instead of val.
|
||||
(allocate_dtv_entry): New function.
|
||||
(allocate_and_init): Return struct dtv_pointer. Call
|
||||
allocate_dtv_entry instead of __libc_memalign.
|
||||
(_dl_update_slotinfo): Free to_free member of struct dtv_pointer
|
||||
instead of val.
|
||||
(tls_get_addr_tail): Set to_free member of struct dtv_pointer
|
||||
instead of is_static. Adjust call to allocate_and_init.
|
||||
* nptl/allocatestack.c (get_cached_stack): Free to_free member of
|
||||
struct dtv_pointer instead of val.
|
||||
|
||||
2015-03-17 Alexandre Oliva <aoliva@redhat.com>
|
||||
|
||||
[BZ #17090]
|
||||
[BZ #17620]
|
||||
[BZ #17621]
|
||||
[BZ #17628]
|
||||
* NEWS: Update.
|
||||
* elf/dl-tls.c (_dl_update_slotinfo): Clean up outdated DTV
|
||||
entries with Static TLS too. Skip entries past the end of the
|
||||
allocated DTV, from Alan Modra.
|
||||
(tls_get_addr_tail): Update to glibc_likely/unlikely. Move
|
||||
Static TLS DTV entry set up from...
|
||||
(_dl_allocate_tls_init): ... here (fix modid assertion), ...
|
||||
* elf/dl-reloc.c (_dl_nothread_init_static_tls): ... here...
|
||||
* nptl/allocatestack.c (init_one_static_tls): ... and here...
|
||||
* elf/dlopen.c (dl_open_worker): Drop l_tls_modid upper bound
|
||||
for Static TLS.
|
||||
* elf/tlsdeschtab.h (map_generation): Return size_t. Check
|
||||
that the slot we find is associated with the given map before
|
||||
using its generation count.
|
||||
* nptl_db/db_info.c: Include ldsodefs.h.
|
||||
(rtld_global, dtv_slotinfo_list, dtv_slotinfo): New typedefs.
|
||||
* nptl_db/structs.def (DB_RTLD_VARIABLE): New macro.
|
||||
(DB_MAIN_VARIABLE, DB_RTLD_GLOBAL_FIELD): Likewise.
|
||||
(link_map::l_tls_offset): New struct field.
|
||||
(dtv_t::counter): Likewise.
|
||||
(rtld_global): New struct.
|
||||
(_rtld_global): New rtld variable.
|
||||
(dl_tls_dtv_slotinfo_list): New rtld global field.
|
||||
(dtv_slotinfo_list): New struct.
|
||||
(dtv_slotinfo): Likewise.
|
||||
* nptl_db/td_symbol_list.c: Drop gnu/lib-names.h include.
|
||||
(td_lookup): Rename to...
|
||||
(td_mod_lookup): ... this. Use new mod parameter instead of
|
||||
LIBPTHREAD_SO.
|
||||
* nptl_db/td_thr_tlsbase.c: Include link.h.
|
||||
(dtv_slotinfo_list, dtv_slotinfo): New functions.
|
||||
(td_thr_tlsbase): Check DTV generation. Compute Static TLS
|
||||
addresses even if the DTV is out of date or missing them.
|
||||
* nptl_db/fetch-value.c (_td_locate_field): Do not refuse to
|
||||
index zero-length arrays.
|
||||
* nptl_db/thread_dbP.h: Include gnu/lib-names.h.
|
||||
(td_lookup): Make it a macro implemented in terms of...
|
||||
(td_mod_lookup): ... this declaration.
|
||||
* nptl_db/db-symbols.awk (DB_RTLD_VARIABLE): Override.
|
||||
(DB_MAIN_VARIABLE): Likewise.
|
||||
|
||||
2016-06-20 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
Consolidate machine-agnostic DTV definitions in <dl-dtv.h>.
|
||||
* sysdeps/generic/dl-dtv.h: New file.
|
||||
* sysdeps/aarch64/dl-tls.h (TLS_DTV_UNALLOCATED): Remove.
|
||||
* sysdeps/aarch64/nptl/tls.h: Include <dl-dtv.h>.
|
||||
(dtv_t): Remove.
|
||||
* sysdeps/alpha/dl-tls.h (TLS_DTV_UNALLOCATED): Remove.
|
||||
* sysdeps/alpha/nptl/tls.h: Include <dl-dtv.h>.
|
||||
(dtv_t): Remove.
|
||||
* sysdeps/arm/dl-tls.h (TLS_DTV_UNALLOCATED): Remove.
|
||||
* sysdeps/arm/nptl/tls.h: Include <dl-dtv.h>.
|
||||
(dtv_t): Remove.
|
||||
* sysdeps/hppa/dl-tls.h (TLS_DTV_UNALLOCATED): Remove.
|
||||
* sysdeps/hppa/nptl/tls.h: Include <dl-dtv.h>.
|
||||
(dtv_t): Remove.
|
||||
* sysdeps/i386/dl-tls.h (TLS_DTV_UNALLOCATED): Remove.
|
||||
* sysdeps/i386/nptl/tls.h: Include <dl-dtv.h>.
|
||||
(dtv_t): Remove.
|
||||
* sysdeps/ia64/dl-tls.h (TLS_DTV_UNALLOCATED): Remove.
|
||||
* sysdeps/ia64/nptl/tls.h: Include <dl-dtv.h>.
|
||||
(dtv_t): Remove.
|
||||
* sysdeps/m68k/dl-tls.h (TLS_DTV_UNALLOCATED): Remove.
|
||||
* sysdeps/m68k/nptl/tls.h: Include <dl-dtv.h>.
|
||||
(dtv_t): Remove.
|
||||
* sysdeps/mach/hurd/i386/tls.h: Include <dl-dtv.h>.
|
||||
(dtv_t): Remove.
|
||||
* sysdeps/microblaze/dl-tls.h (TLS_DTV_UNALLOCATED): Remove.
|
||||
* sysdeps/microblaze/nptl/tls.h: Include <dl-dtv.h>.
|
||||
(dtv_t): Remove.
|
||||
* sysdeps/mips/dl-tls.h (TLS_DTV_UNALLOCATED): Remove.
|
||||
* sysdeps/mips/nptl/tls.h: Include <dl-dtv.h>.
|
||||
(dtv_t): Remove.
|
||||
* sysdeps/nios2/dl-tls.h (TLS_DTV_UNALLOCATED): Remove.
|
||||
* sysdeps/nios2/nptl/tls.h: Include <dl-dtv.h>.
|
||||
(dtv_t): Remove.
|
||||
* sysdeps/powerpc/dl-tls.h (TLS_DTV_UNALLOCATED): Remove.
|
||||
* sysdeps/powerpc/nptl/tls.h: Include <dl-dtv.h>.
|
||||
(dtv_t): Remove.
|
||||
* sysdeps/s390/dl-tls.h (TLS_DTV_UNALLOCATED): Remove.
|
||||
* sysdeps/s390/nptl/tls.h: Include <dl-dtv.h>.
|
||||
(dtv_t): Remove.
|
||||
* sysdeps/sh/dl-tls.h (TLS_DTV_UNALLOCATED): Remove.
|
||||
* sysdeps/sh/nptl/tls.h: Include <dl-dtv.h>.
|
||||
(dtv_t): Remove.
|
||||
* sysdeps/sparc/dl-tls.h (TLS_DTV_UNALLOCATED): Remove.
|
||||
* sysdeps/sparc/nptl/tls.h: Include <dl-dtv.h>.
|
||||
(dtv_t): Remove.
|
||||
* sysdeps/x86_64/dl-tls.h (TLS_DTV_UNALLOCATED): Remove.
|
||||
* sysdeps/x86_64/nptl/tls.h: Include <dl-dtv.h>.
|
||||
(dtv_t): Remove.
|
||||
|
||||
2016-04-14 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
[BZ #19431]
|
||||
Run the malloc fork handler as late as possible to avoid deadlocks.
|
||||
* malloc/malloc-internal.h: New file.
|
||||
* malloc/malloc.c: Include it.
|
||||
* malloc/arena.c (ATFORK_MEM): Remove.
|
||||
(__malloc_fork_lock_parent): Rename from ptmalloc_lock_all.
|
||||
Update comment.
|
||||
(__malloc_fork_unlock_parent): Rename from ptmalloc_unlock_all.
|
||||
(__malloc_fork_unlock_child): Rename from ptmalloc_unlock_all2.
|
||||
Remove outdated comment.
|
||||
(ptmalloc_init): Do not call thread_atfork. Remove
|
||||
thread_atfork_static.
|
||||
* malloc/tst-malloc-fork-deadlock.c: New file.
|
||||
* Makefile (tests): Add tst-malloc-fork-deadlock.
|
||||
(tst-malloc-fork-deadlock): Link against libpthread.
|
||||
* manual/memory.texi (Aligned Memory Blocks): Update safety
|
||||
annotation comments.
|
||||
* sysdeps/nptl/fork.c (__libc_fork): Call
|
||||
__malloc_fork_lock_parent, __malloc_fork_unlock_parent,
|
||||
__malloc_fork_unlock_child.
|
||||
* sysdeps/mach/hurd/fork.c (__fork): Likewise.
|
||||
|
||||
2015-12-21 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
[BZ #19182]
|
||||
* malloc/arena.c (list_lock): Document lock ordering requirements.
|
||||
(free_list_lock): New lock.
|
||||
(ptmalloc_lock_all): Comment on free_list_lock.
|
||||
(ptmalloc_unlock_all2): Reinitialize free_list_lock.
|
||||
(detach_arena): Update comment. free_list_lock is now needed.
|
||||
(_int_new_arena): Use free_list_lock around detach_arena call.
|
||||
Acquire arena lock after list_lock. Add comment, including FIXME
|
||||
about incorrect synchronization.
|
||||
(get_free_list): Switch to free_list_lock.
|
||||
(reused_arena): Acquire free_list_lock around detach_arena call
|
||||
and attached threads counter update. Add two FIXMEs about
|
||||
incorrect synchronization.
|
||||
(arena_thread_freeres): Switch to free_list_lock.
|
||||
* malloc/malloc.c (struct malloc_state): Update comments to
|
||||
mention free_list_lock.
|
||||
|
||||
2015-11-24 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
Replace MUTEX_INITIALIZER with _LIBC_LOCK_INITIALIZER in generic code.
|
||||
* sysdeps/mach/hurd/libc-lock.h (_LIBC_LOCK_INITIALIZER): Define.
|
||||
(__libc_lock_define_initialized): Use it.
|
||||
* sysdeps/nptl/libc-lockP.h (_LIBC_LOCK_INITIALIZER): Define.
|
||||
* malloc/arena.c (list_lock): Use _LIBC_LOCK_INITIALIZER.
|
||||
* malloc/malloc.c (main_arena): Likewise.
|
||||
* sysdeps/generic/malloc-machine.h (MUTEX_INITIALIZER): Remove.
|
||||
* sysdeps/nptl/malloc-machine.h (MUTEX_INITIALIZER): Remove.
|
||||
|
||||
2015-10-28 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
[BZ# 19048]
|
||||
* malloc/malloc.c (struct malloc_state): Update comment. Add
|
||||
attached_threads member.
|
||||
(main_arena): Initialize attached_threads.
|
||||
* malloc/arena.c (list_lock): Update comment.
|
||||
(ptmalloc_lock_all, ptmalloc_unlock_all): Likewise.
|
||||
(ptmalloc_unlock_all2): Reinitialize arena reference counts.
|
||||
(deattach_arena): New function.
|
||||
(_int_new_arena): Initialize arena reference count and deattach
|
||||
replaced arena.
|
||||
(get_free_list, reused_arena): Update reference count and deattach
|
||||
replaced arena.
|
||||
(arena_thread_freeres): Update arena reference count and only put
|
||||
unreferenced arenas on the free list.
|
||||
|
||||
2015-10-17 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
malloc: Rewrite with explicit TLS access using __thread.
|
||||
* sysdeps/generic/malloc-machine.h (tsd_key_t, tsd_key_create)
|
||||
(tsd_setspecific, tsd_getspecific): Remove.
|
||||
* sysdeps/mach/hurd/malloc-machine.h (tsd_key_t, tsd_key_create)
|
||||
(tsd_setspecific, tsd_getspecific): Likewise.
|
||||
* sysdeps/nptl/malloc-machine.h (tsd_key_t, tsd_key_create)
|
||||
(tsd_setspecific, tsd_getspecific): Likewise.
|
||||
* malloc/arena.c (thread_arena): New TLS variable.
|
||||
(arena_key): Remove variable.
|
||||
(arena_get): Use thread_arena.
|
||||
(arena_lookup): Remove macro.
|
||||
(malloc_atfork, free_atfork, ptmalloc_lock_all)
|
||||
(ptmalloc_unlock_all, ptmalloc_unlock_all2, ptmalloc_init)
|
||||
(_int_new_arena, get_free_list, reused_arena)
|
||||
(arena_thread_freeres): Use thread_arena.
|
||||
* manual/memory.texi (Basic Allocation): Remove arena_lookup,
|
||||
tsd_getspecific, tsd_setspecific from safety annotations.
|
||||
(Allocating Cleared Space): Remove arena_lookup from safety
|
||||
annotations.
|
||||
|
||||
2015-02-18 Siddhesh Poyarekar <siddhesh@redhat.com>
|
||||
|
||||
* malloc/malloc.c (__libc_malloc): Consolidate arena_lookup and
|
||||
arena_lock into a single arena_get.
|
||||
|
||||
2015-05-22 Roland McGrath <roland@hack.frob.com>
|
||||
|
||||
* nptl/nptl-init.c (__pthread_initialize_minimal_internal):
|
||||
Use a separate INTERNAL_SYSCALL_DECL (err); in a local scope
|
||||
for each INTERNAL_SYSCALL use.
|
||||
|
||||
2016-06-03 Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
* nptl/pthreadP.h (prio_inherit_missing): Change name to
|
||||
__prio_inherit_missing.
|
||||
(USE_REQUEUE_PI): Remove define.
|
||||
(use_requeue_pi): New function.
|
||||
* nptl/pthread_cond_broadcast.c [__ASSUME_REQUEUE_PI]
|
||||
(__pthread_cond_broadcast): Remove ifdef.
|
||||
(USE_REQUEUE_PI): Change to use_requeue_pi.
|
||||
* nptl/pthread_cond_signal.c [__ASSUME_REQUEUE_PI]
|
||||
(__pthread_cond_signal): Remove ifdef.
|
||||
(USE_REQUEUE_PI): Change to use_requeue_pi.
|
||||
* nptl/pthread_cond_timedwait.c [__ASSUME_REQUEUE_PI]
|
||||
(__pthread_cond_timedwait): Remove ifdef.
|
||||
(USE_REQUEUE_PI): Change to use_requeue_pi.
|
||||
( nptl/pthread_cond_wait.c [__ASSUME_REQUEUE_PI]
|
||||
(__pthread_cond_wait): Remove ifdef.
|
||||
(USE_REQUEUE_PI): Change to use_requeue_pi.
|
||||
* nptl/pthread_mutex_init.c (prio_inherit_missing): Remove 'static'
|
||||
qualifier and change name to __prio_inherit_missing.
|
||||
|
||||
* nptl/nptl-init.c [__ASSUME_SET_ROBUST_LIST]
|
||||
(__set_robust_list_avail): Remove define.
|
||||
[__NR_set_robust_list] (__pthread_initialize_minimal_internal):
|
||||
Likewise.
|
||||
* nptl/pthreadP.h [__ASSUME_SET_ROBUST_LIST]
|
||||
(__set_robust_list_avail): Likewise.
|
||||
* nptl/pthread_create.c
|
||||
[__NR_set_robust_list && !__ASSUME_SET_ROBUST_LIST]
|
||||
(START_THREAD_DEFN): Likewise.
|
||||
* nptl/pthread_mutex_init.c [!__ASSUME_SET_ROBUST_LIST]
|
||||
(__pthread_mutex_init): Likewise.
|
||||
* sysdeps/unix/sysv/linux/arm/kernel-features.h
|
||||
(__ASSUME_SET_ROBUST_LIST): Likewise.
|
||||
* sysdeps/unix/sysv/linux/kernel-features.h:
|
||||
(__ASSUME_SET_ROBUST_LIST): Likewise.
|
||||
* sysdeps/unix/sysv/linux/m68k/kernel-features.h:
|
||||
(__ASSUME_SET_ROBUST_LIST): Likewise.
|
||||
* sysdeps/unix/sysv/linux/mips/kernel-features.h:
|
||||
(__ASSUME_SET_ROBUST_LIST): Likewise.
|
||||
* sysdeps/unix/sysv/linux/sparc/kernel-features.h:
|
||||
(__ASSUME_SET_ROBUST_LIST): Likewise.
|
||||
|
||||
* nptl/pthread_mutex_init.c [__ASSUME_FUTEX_LOCK_PI]
|
||||
(prio_inherit_missing): Remove define.
|
||||
* sysdeps/unix/sysv/linux/arm/kernel-features.h
|
||||
(__ASSUME_FUTEX_LOCK_PI): Likewise.
|
||||
* sysdeps/unix/sysv/linux/kernel-features.h (__ASSUME_FUTEX_LOCK_PI):
|
||||
Likewise.
|
||||
* sysdeps/unix/sysv/linux/m68k/kernel-features.h
|
||||
(__ASSUME_FUTEX_LOCK_PI): Likewise.
|
||||
* sysdeps/unix/sysv/linux/mips/kernel-features.h
|
||||
(__ASSUME_FUTEX_LOCK_PI): Likewise.
|
||||
* sysdeps/unix/sysv/linux/sparc/kernel-features.h
|
||||
(__ASSUME_FUTEX_LOCK_PI): Likewise.
|
||||
|
||||
2016-05-09 Yvan Roux <yvan.roux@linaro.org>
|
||||
|
||||
* stdlib/setenv.c (unsetenv): Fix ambiguous 'else'.
|
||||
* nis/nis_call.c (nis_server_cache_add): Likewise.
|
||||
|
||||
2016-04-28 Stefan Liebler <stli@linux.vnet.ibm.com>
|
||||
|
||||
[BZ #18508]
|
||||
* stdlib/Makefile ($(objpfx)tst-makecontext3):
|
||||
Depend on $(libdl).
|
||||
* stdlib/tst-makecontext.c (cf): Test if _Unwind_Backtrace
|
||||
is not called infinitely times.
|
||||
(backtrace_helper): New function.
|
||||
(trace_arg): New struct.
|
||||
(st1): Enlarge stack size.
|
||||
* sysdeps/unix/sysv/linux/s390/s390-32/__makecontext_ret.S:
|
||||
(__makecontext_ret): Omit cfi_startproc and cfi_endproc.
|
||||
* sysdeps/unix/sysv/linux/s390/s390-64/__makecontext_ret.S:
|
||||
Likewise.
|
||||
|
||||
2016-04-28 Stefan Liebler <stli@linux.vnet.ibm.com>
|
||||
|
||||
[BZ #18080]
|
||||
* sysdeps/unix/sysv/linux/s390/s390-32/setcontext.S
|
||||
(__setcontext): Use SIG_SETMASK instead of SIG_BLOCK.
|
||||
* sysdeps/unix/sysv/linux/s390/s390-64/setcontext.S
|
||||
(__setcontext): Likewise.
|
||||
* sysdeps/unix/sysv/linux/s390/s390-32/swapcontext.S
|
||||
(__swapcontext): Use SIG_SETMASK instead of SIG_BLOCK.
|
||||
Call rt_sigprocmask syscall one time to set new signal mask
|
||||
and retrieve the current signal mask instead of two calls.
|
||||
* sysdeps/unix/sysv/linux/s390/s390-64/swapcontext.S
|
||||
(__swapcontext): Likewise.
|
||||
* stdlib/Makefile (tests): Add new testcase tst-setcontext2.
|
||||
* stdlib/tst-setcontext2.c: New file.
|
||||
|
||||
2016-04-09 Mike Frysinger <vapier@gentoo.org>
|
||||
|
||||
* sysdeps/x86_64/configure.ac: Change == to = when calling test.
|
||||
* sysdeps/x86_64/configure: Likewise.
|
||||
|
||||
2016-04-04 Stefan Liebler <stli@linux.vnet.ibm.com>
|
||||
|
||||
* sysdeps/s390/bits/link.h: (La_s390_vr) New typedef.
|
||||
(La_s390_32_regs): Append vector register lr_v24-lr_v31.
|
||||
(La_s390_64_regs): Likewise.
|
||||
(La_s390_32_retval): Append vector register lrv_v24.
|
||||
(La_s390_64_retval): Likeweise.
|
||||
* sysdeps/s390/s390-32/dl-trampoline.h (_dl_runtime_profile):
|
||||
Handle extended structs La_s390_32_regs and La_s390_32_retval.
|
||||
* sysdeps/s390/s390-64/dl-trampoline.h (_dl_runtime_profile):
|
||||
Handle extended structs La_s390_64_regs and La_s390_64_retval.
|
||||
|
||||
2016-04-04 Stefan Liebler <stli@linux.vnet.ibm.com>
|
||||
|
||||
* sysdeps/s390/s390-32/dl-trampoline.S: Include dl-trampoline.h twice
|
||||
to create a non-vector/vector version for _dl_runtime_resolve and
|
||||
_dl_runtime_profile. Move implementation to ...
|
||||
* sysdeps/s390/s390-32/dl-trampoline.h: ... here.
|
||||
(_dl_runtime_resolve) Save and restore fpr/vrs.
|
||||
(_dl_runtime_profile) Save and restore vrs and fix some issues
|
||||
if _dl_call_pltexit is called.
|
||||
* sysdeps/s390/s390-32/dl-machine.h (elf_machine_runtime_setup):
|
||||
Choose the correct resolver function if running on a machine with vx.
|
||||
* sysdeps/s390/s390-64/dl-trampoline.S: Include dl-trampoline.h twice
|
||||
to create a non-vector/vector version for _dl_runtime_resolve and
|
||||
_dl_runtime_profile. Move implementation to ...
|
||||
* sysdeps/s390/s390-64/dl-trampoline.h: ... here.
|
||||
(_dl_runtime_resolve) Save and restore fpr/vrs.
|
||||
(_dl_runtime_profile) Save and restore vrs and fix some issues
|
||||
* sysdeps/s390/s390-64/dl-machine.h: (elf_machine_runtime_setup):
|
||||
Choose the correct resolver function if running on a machine with vx.
|
||||
|
||||
2016-04-04 Stefan Liebler <stli@linux.vnet.ibm.com>
|
||||
|
||||
* config.h.in (HAVE_S390_VX_ASM_SUPPORT): New macro undefine.
|
||||
* sysdeps/s390/configure.ac: Add test for S390 vector instruction
|
||||
assembler support.
|
||||
* sysdeps/s390/configure: Regenerated.
|
||||
|
||||
2016-04-04 Stefan Liebler <stli@linux.vnet.ibm.com>
|
||||
|
||||
* sysdeps/s390/dl-procinfo.c (_dl_s390_cap_flags): Add z13.
|
||||
* sysdeps/s390/dl-procinfo.h (_DL_PLATFORMS_COUNT): Increased.
|
||||
|
||||
2016-04-04 Stefan Liebler <stli@linux.vnet.ibm.com>
|
||||
|
||||
* sysdeps/s390/dl-procinfo.c (_dl_s390_platforms): Add vector flag.
|
||||
* sysdeps/s390/dl-procinfo.h: Add vector capability.
|
||||
* sysdeps/unix/sysv/linux/s390/bits/hwcap.h (HWCAP_S390_VX): Define.
|
||||
|
||||
2016-03-07 Hongjiu Zhang <noctuorare@gmail.com>
|
||||
|
||||
* elf/sln.c (makesymlink): Change struct stat to stat64, and lstat
|
||||
to lstat64.
|
||||
|
||||
2016-03-02 Stefan Liebler <stli@linux.vnet.ibm.com>
|
||||
|
||||
[BZ #19682]
|
||||
* sysdeps/unix/sysv/linux/s390/s390-64/syscalls.list:
|
||||
Remove socketcall syscalls.
|
||||
|
||||
2016-02-15 Carlos O'Donell <carlos@redhat.com>
|
||||
|
||||
[BZ #18665]
|
||||
* resolv/nss_dns/dns-host.c (gaih_getanswer_slice): Always set
|
||||
*herrno_p.
|
||||
(gaih_getanswer): Document functional behviour. Return tryagain
|
||||
if any result is tryagain.
|
||||
* resolv/res_query.c (__libc_res_nsearch): Set buffer size to zero
|
||||
when freed.
|
||||
* resolv/res_send.c: Add copyright text.
|
||||
(__libc_res_nsend): Document that MAXPACKET is expected.
|
||||
(send_vc): Document. Remove buffer reuse.
|
||||
(send_dg): Document. Remove buffer reuse. Set *thisanssizp to set the
|
||||
size of the buffer. Add Dprint for truncated UDP buffer.
|
||||
|
||||
2016-02-12 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
* misc/bug18240.c (do_test): Set RLIMIT_AS.
|
||||
|
||||
2016-01-27 Paul Eggert <eggert@cs.ucla.edu>
|
||||
|
||||
[BZ #18240]
|
||||
* misc/hsearch_r.c (isprime, __hcreate_r): Protect against
|
||||
unsigned int wraparound.
|
||||
|
||||
2016-01-27 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
[BZ #18240]
|
||||
* misc/bug18240.c: New test.
|
||||
* misc/Makefile (tests): Add it.
|
||||
|
||||
2015-08-25 Ondřej Bílka <neleai@seznam.cz>
|
||||
|
||||
[BZ #18240]
|
||||
* misc/hsearch_r.c (__hcreate_r): Handle overflow.
|
||||
|
||||
2015-09-26 Paul Pluzhnikov <ppluzhnikov@google.com>
|
||||
|
||||
[BZ #18985]
|
||||
* time/strftime_l.c (a_wkday, f_wkday, a_month, f_month): Range check.
|
||||
(__strftime_internal): Likewise.
|
||||
* time/tst-strftime.c (do_bz18985): New test.
|
||||
(do_test): Call it.
|
||||
|
||||
2015-08-08 Paul Pluzhnikov <ppluzhnikov@google.com>
|
||||
|
||||
[BZ #17905]
|
||||
* catgets/Makefile (tst-catgets-mem): New test.
|
||||
* catgets/catgets.c (catopen): Don't use unbounded alloca.
|
||||
* catgets/open_catalog.c (__open_catalog): Likewise.
|
||||
* catgets/tst-catgets.c (do_bz17905): Test unbounded alloca.
|
||||
|
||||
2015-05-01 Szabolcs Nagy <szabolcs.nagy@arm.com>
|
||||
|
||||
* config.h.in (HAVE_AARCH64_BE): Add.
|
||||
|
||||
2015-07-08 Mike Frysinger <vapier@gentoo.org>
|
||||
|
||||
* nscd/selinux.c: Delete selinux/flask.h include.
|
||||
|
||||
2015-03-02 Andreas Schwab <schwab@suse.de>
|
||||
|
||||
* elf/Makefile ($(elf-objpfx)runtime-linker.st): Fix typo in
|
||||
variable name.
|
||||
|
||||
2015-04-29 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
[BZ #18007]
|
||||
* nss/nss_files/files-XXX.c (CONCAT): Always enable stayopen.
|
||||
(CVE-2014-8121)
|
||||
* nss/tst-nss-getpwent.c: New file.
|
||||
* nss/Makefile (tests): Add new test.
|
||||
|
||||
2015-08-28 Mike Frysinger <vapier@gentoo.org>
|
||||
|
||||
[BZ #18887]
|
||||
* misc/Makefile (tests): Add tst-mntent-blank-corrupt and
|
||||
tst-mntent-blank-passno.
|
||||
* misc/mntent_r.c (__getmntent_r): Do not read past buffer[0].
|
||||
* misc/tst-mntent-blank-corrupt.c: New test.
|
||||
* misc/tst-mntent-blank-passno.c: New test ripped from ...
|
||||
* misc/tst-mntent.c (do_test): ... here.
|
||||
|
||||
2015-07-27 Mike Frysinger <vapier@gentoo.org>
|
||||
|
||||
* sysdeps/ia64/bits/atomic.h (atomic_exchange_and_add): Define
|
||||
directly in terms of __sync_fetch_and_add and delete (int) cast.
|
||||
|
||||
2015-02-22 Paul Pluzhnikov <ppluzhnikov@google.com>
|
||||
|
||||
[BZ #17269]
|
||||
* libio/wstrops.c (_IO_wstr_overflow): Guard against integer overflow
|
||||
(enlarge_userbuf): Likewise.
|
||||
|
||||
2015-02-26 Andreas Schwab <schwab@suse.de>
|
||||
|
||||
[BZ #18032]
|
||||
* posix/fnmatch_loop.c (FCT): Remove extra increment when skipping
|
||||
over collating symbol inside a bracket expression. Minor cleanup.
|
||||
* posix/tst-fnmatch3.c (do_test): Add test case.
|
||||
|
||||
2015-07-21 Mike Frysinger <vapier@gentoo.org>
|
||||
|
||||
[BZ #18694]
|
||||
* sysdeps/unix/sysv/linux/sparc/bits/sigaction.h: Include
|
||||
bits/wordsize.h.
|
||||
(sigaction): Declare __glibc_reserved0 only when __WORDSIZE is 64.
|
||||
|
||||
2015-04-21 Arjun Shankar <arjun.is@lostca.se>
|
||||
|
||||
[BZ #18287]
|
||||
* resolv/nss_dns/dns-host.c (getanswer_r): Adjust buffer length
|
||||
based on padding. (CVE-2015-1781)
|
||||
|
||||
2015-02-10 Evangelos Foutras <evangelos@foutrelis.com>
|
||||
|
||||
[BZ #17949]
|
||||
* sysdeps/i386/i686/multiarch/mempcpy_chk.S: Fix position of
|
||||
jump label.
|
||||
|
||||
2015-02-06 Carlos O'Donell <carlos@systemhalted.org>
|
||||
|
||||
* version.h (RELEASE): Set to "stable".
|
||||
@@ -7,6 +604,7 @@
|
||||
* sysdeps/unix/sysv/linux/hppa/pthread.h: Sync with pthread.h.
|
||||
|
||||
2015-02-05 Paul Pluzhnikov <ppluzhnikov@google.com>
|
||||
Paul Eggert <eggert@cs.ucla.edu>
|
||||
|
||||
[BZ #16618]
|
||||
* stdio-common/tst-sscanf.c (main): Test for buffer overflow.
|
||||
|
||||
@@ -5,6 +5,43 @@ See the end for copying conditions.
|
||||
Please send GNU C library bug reports via <http://sourceware.org/bugzilla/>
|
||||
using `glibc' in the "product" field.
|
||||
|
||||
Version 2.21.1
|
||||
|
||||
* The following bugs are resolved with this release:
|
||||
|
||||
16512, 17090, 17269, 17620, 17621, 17628, 17905, 17949, 18007, 18032,
|
||||
18078, 18080, 18240, 18287, 18508, 18694, 18887, 18985, 19048, 19682.
|
||||
|
||||
* A stack-based buffer overflow was found in libresolv when invoked from
|
||||
libnss_dns, allowing specially crafted DNS responses to seize control
|
||||
of execution flow in the DNS client. The buffer overflow occurs in
|
||||
the functions send_dg (send datagram) and send_vc (send TCP) for the
|
||||
NSS module libnss_dns.so.2 when calling getaddrinfo with AF_UNSPEC
|
||||
family. The use of AF_UNSPEC triggers the low-level resolver code to
|
||||
send out two parallel queries for A and AAAA. A mismanagement of the
|
||||
buffers used for those queries could result in the response of a query
|
||||
writing beyond the alloca allocated buffer created by
|
||||
_nss_dns_gethostbyname4_r. Buffer management is simplified to remove
|
||||
the overflow. Thanks to the Google Security Team and Red Hat for
|
||||
reporting the security impact of this issue, and Robert Holiday of
|
||||
Ciena for reporting the related bug 18665. (CVE-2015-7547)
|
||||
|
||||
* A buffer overflow in gethostbyname_r and related functions performing DNS
|
||||
requests has been fixed. If the NSS functions were called with a
|
||||
misaligned buffer, the buffer length change due to pointer alignment was
|
||||
not taken into account. This could result in application crashes or,
|
||||
potentially arbitrary code execution, using crafted, but syntactically
|
||||
valid DNS responses. (CVE-2015-1781)
|
||||
|
||||
* The 32-bit sparc sigaction ABI was inadvertently broken in the 2.20 and 2.21
|
||||
releases. It has been fixed to match 2.19 and older, but binaries built
|
||||
against 2.20 and 2.21 might need to be recompiled. See BZ#18694.
|
||||
|
||||
* CVE-2014-8121 The NSS files backend would reset the file pointer used by
|
||||
the get*ent functions if any of the query functions for the same database
|
||||
are used during the iteration, causing a denial-of-service condition in
|
||||
some applications.
|
||||
|
||||
Version 2.21
|
||||
|
||||
* The following bugs are resolved with this release:
|
||||
@@ -21,10 +58,11 @@ Version 2.21
|
||||
17801, 17803, 17806, 17834, 17844, 17848, 17868, 17869, 17870, 17885,
|
||||
17892.
|
||||
|
||||
* CVE-2015-1472 Under certain conditions wscanf can allocate too little
|
||||
memory for the to-be-scanned arguments and overflow the allocated
|
||||
buffer. The implementation now correctly computes the required buffer
|
||||
size when using malloc.
|
||||
* CVE-2015-1472 CVE-2015-1473 Under certain conditions wscanf can allocate
|
||||
too little memory for the to-be-scanned arguments and overflow the
|
||||
allocated buffer. The implementation now correctly computes the required
|
||||
buffer size when using malloc, and switches to malloc from alloca as
|
||||
intended.
|
||||
|
||||
* A new semaphore algorithm has been implemented in generic C code for all
|
||||
machines. Previous custom assembly implementations of semaphore were
|
||||
|
||||
+8
-1
@@ -34,6 +34,7 @@ test-srcs = test-gencat
|
||||
ifeq ($(run-built-tests),yes)
|
||||
tests-special += $(objpfx)de/libc.cat $(objpfx)test1.cat $(objpfx)test2.cat \
|
||||
$(objpfx)sample.SJIS.cat $(objpfx)test-gencat.out
|
||||
tests-special += $(objpfx)tst-catgets-mem.out
|
||||
endif
|
||||
|
||||
gencat-modules = xmalloc
|
||||
@@ -50,9 +51,11 @@ catgets-CPPFLAGS := -DNLSPATH='"$(msgcatdir)/%L/%N:$(msgcatdir)/%L/LC_MESSAGES/%
|
||||
|
||||
generated += de.msg test1.cat test1.h test2.cat test2.h sample.SJIS.cat \
|
||||
test-gencat.h
|
||||
generated += tst-catgets.mtrace tst-catgets-mem.out
|
||||
|
||||
generated-dirs += de
|
||||
|
||||
tst-catgets-ENV = NLSPATH="$(objpfx)%l/%N.cat" LANG=de
|
||||
tst-catgets-ENV = NLSPATH="$(objpfx)%l/%N.cat" LANG=de MALLOC_TRACE=$(objpfx)tst-catgets.mtrace
|
||||
|
||||
ifeq ($(run-built-tests),yes)
|
||||
# This test just checks whether the program produces any error or not.
|
||||
@@ -86,4 +89,8 @@ $(objpfx)test-gencat.out: test-gencat.sh $(objpfx)test-gencat \
|
||||
$(objpfx)sample.SJIS.cat: sample.SJIS $(objpfx)gencat
|
||||
$(built-program-cmd) -H $(objpfx)test-gencat.h < $(word 1,$^) > $@; \
|
||||
$(evaluate-test)
|
||||
|
||||
$(objpfx)tst-catgets-mem.out: $(objpfx)tst-catgets.out
|
||||
$(common-objpfx)malloc/mtrace $(objpfx)tst-catgets.mtrace > $@; \
|
||||
$(evaluate-test)
|
||||
endif
|
||||
|
||||
+12
-7
@@ -16,7 +16,6 @@
|
||||
License along with the GNU C Library; if not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <alloca.h>
|
||||
#include <errno.h>
|
||||
#include <locale.h>
|
||||
#include <nl_types.h>
|
||||
@@ -35,6 +34,7 @@ catopen (const char *cat_name, int flag)
|
||||
__nl_catd result;
|
||||
const char *env_var = NULL;
|
||||
const char *nlspath = NULL;
|
||||
char *tmp = NULL;
|
||||
|
||||
if (strchr (cat_name, '/') == NULL)
|
||||
{
|
||||
@@ -54,7 +54,10 @@ catopen (const char *cat_name, int flag)
|
||||
{
|
||||
/* Append the system dependent directory. */
|
||||
size_t len = strlen (nlspath) + 1 + sizeof NLSPATH;
|
||||
char *tmp = alloca (len);
|
||||
tmp = malloc (len);
|
||||
|
||||
if (__glibc_unlikely (tmp == NULL))
|
||||
return (nl_catd) -1;
|
||||
|
||||
__stpcpy (__stpcpy (__stpcpy (tmp, nlspath), ":"), NLSPATH);
|
||||
nlspath = tmp;
|
||||
@@ -65,16 +68,18 @@ catopen (const char *cat_name, int flag)
|
||||
|
||||
result = (__nl_catd) malloc (sizeof (*result));
|
||||
if (result == NULL)
|
||||
/* We cannot get enough memory. */
|
||||
return (nl_catd) -1;
|
||||
|
||||
if (__open_catalog (cat_name, nlspath, env_var, result) != 0)
|
||||
{
|
||||
/* We cannot get enough memory. */
|
||||
result = (nl_catd) -1;
|
||||
}
|
||||
else if (__open_catalog (cat_name, nlspath, env_var, result) != 0)
|
||||
{
|
||||
/* Couldn't open the file. */
|
||||
free ((void *) result);
|
||||
return (nl_catd) -1;
|
||||
result = (nl_catd) -1;
|
||||
}
|
||||
|
||||
free (tmp);
|
||||
return (nl_catd) result;
|
||||
}
|
||||
|
||||
|
||||
+14
-9
@@ -47,6 +47,7 @@ __open_catalog (const char *cat_name, const char *nlspath, const char *env_var,
|
||||
size_t tab_size;
|
||||
const char *lastp;
|
||||
int result = -1;
|
||||
char *buf = NULL;
|
||||
|
||||
if (strchr (cat_name, '/') != NULL || nlspath == NULL)
|
||||
fd = open_not_cancel_2 (cat_name, O_RDONLY);
|
||||
@@ -57,23 +58,23 @@ __open_catalog (const char *cat_name, const char *nlspath, const char *env_var,
|
||||
if (__glibc_unlikely (bufact + (n) >= bufmax)) \
|
||||
{ \
|
||||
char *old_buf = buf; \
|
||||
bufmax += 256 + (n); \
|
||||
buf = (char *) alloca (bufmax); \
|
||||
memcpy (buf, old_buf, bufact); \
|
||||
bufmax += (bufmax < 256 + (n)) ? 256 + (n) : bufmax; \
|
||||
buf = realloc (buf, bufmax); \
|
||||
if (__glibc_unlikely (buf == NULL)) \
|
||||
{ \
|
||||
free (old_buf); \
|
||||
return -1; \
|
||||
} \
|
||||
}
|
||||
|
||||
/* The RUN_NLSPATH variable contains a colon separated list of
|
||||
descriptions where we expect to find catalogs. We have to
|
||||
recognize certain % substitutions and stop when we found the
|
||||
first existing file. */
|
||||
char *buf;
|
||||
size_t bufact;
|
||||
size_t bufmax;
|
||||
size_t bufmax = 0;
|
||||
size_t len;
|
||||
|
||||
buf = NULL;
|
||||
bufmax = 0;
|
||||
|
||||
fd = -1;
|
||||
while (*run_nlspath != '\0')
|
||||
{
|
||||
@@ -188,7 +189,10 @@ __open_catalog (const char *cat_name, const char *nlspath, const char *env_var,
|
||||
|
||||
/* Avoid dealing with directories and block devices */
|
||||
if (__builtin_expect (fd, 0) < 0)
|
||||
return -1;
|
||||
{
|
||||
free (buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (__builtin_expect (__fxstat64 (_STAT_VER, fd, &st), 0) < 0)
|
||||
goto close_unlock_return;
|
||||
@@ -325,6 +329,7 @@ __open_catalog (const char *cat_name, const char *nlspath, const char *env_var,
|
||||
/* Release the lock again. */
|
||||
close_unlock_return:
|
||||
close_not_cancel_no_status (fd);
|
||||
free (buf);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
#include <assert.h>
|
||||
#include <mcheck.h>
|
||||
#include <nl_types.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
|
||||
static const char *msgs[] =
|
||||
@@ -12,6 +15,33 @@ static const char *msgs[] =
|
||||
};
|
||||
#define nmsgs (sizeof (msgs) / sizeof (msgs[0]))
|
||||
|
||||
|
||||
/* Test for unbounded alloca. */
|
||||
static int
|
||||
do_bz17905 (void)
|
||||
{
|
||||
char *buf;
|
||||
struct rlimit rl;
|
||||
nl_catd result;
|
||||
|
||||
const int sz = 1024 * 1024;
|
||||
|
||||
getrlimit (RLIMIT_STACK, &rl);
|
||||
rl.rlim_cur = sz;
|
||||
setrlimit (RLIMIT_STACK, &rl);
|
||||
|
||||
buf = malloc (sz + 1);
|
||||
memset (buf, 'A', sz);
|
||||
buf[sz] = '\0';
|
||||
setenv ("NLSPATH", buf, 1);
|
||||
|
||||
result = catopen (buf, NL_CAT_LOCALE);
|
||||
assert (result == (nl_catd) -1);
|
||||
|
||||
free (buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define ROUNDS 5
|
||||
|
||||
static int
|
||||
@@ -62,6 +92,7 @@ do_test (void)
|
||||
}
|
||||
}
|
||||
|
||||
result += do_bz17905 ();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -94,6 +94,9 @@
|
||||
/* Define if assembler supports AVX512. */
|
||||
#undef HAVE_AVX512_ASM_SUPPORT
|
||||
|
||||
/* Define if assembler supports vector instructions on S390. */
|
||||
#undef HAVE_S390_VX_ASM_SUPPORT
|
||||
|
||||
/* Define if assembler supports Intel MPX. */
|
||||
#undef HAVE_MPX_SUPPORT
|
||||
|
||||
@@ -114,6 +117,9 @@
|
||||
include/libc-symbols.h that avoid PLT slots in the shared objects. */
|
||||
#undef NO_HIDDEN
|
||||
|
||||
/* AArch64 big endian ABI */
|
||||
#undef HAVE_AARCH64_BE
|
||||
|
||||
|
||||
/* Defined to some form of __attribute__ ((...)) if the compiler supports
|
||||
a different, more efficient calling convention. */
|
||||
|
||||
+1
-1
@@ -172,7 +172,7 @@ __libc_setup_tls (size_t tcbsize, size_t tcbalign)
|
||||
#else
|
||||
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
|
||||
#endif
|
||||
_dl_static_dtv[2].pointer.is_static = true;
|
||||
_dl_static_dtv[2].pointer.to_free = NULL;
|
||||
/* sbrk gives us zero'd memory, so we don't need to clear the remainder. */
|
||||
memcpy (_dl_static_dtv[2].pointer.val, initimage, filesz);
|
||||
|
||||
|
||||
+1
-1
@@ -358,7 +358,7 @@ $(objpfx)interp.os: $(elf-objpfx)runtime-linker.h
|
||||
|
||||
$(elf-objpfx)runtime-linker.h: $(elf-objpfx)runtime-linker.st; @:
|
||||
$(elf-objpfx)runtime-linker.st: $(common-objpfx)config.make
|
||||
$(name-target-directory)
|
||||
$(make-target-directory)
|
||||
echo '#define RUNTIME_LINKER "$(rtlddir)/$(rtld-installed-name)"' \
|
||||
> ${@:st=T}
|
||||
$(move-if-change) ${@:st=T} ${@:st=h}
|
||||
|
||||
+1
-11
@@ -533,17 +533,7 @@ TLS generation counter wrapped! Please report this."));
|
||||
&& imap->l_tls_blocksize > 0)
|
||||
{
|
||||
/* For static TLS we have to allocate the memory here and
|
||||
now. This includes allocating memory in the DTV. But we
|
||||
cannot change any DTV other than our own. So, if we
|
||||
cannot guarantee that there is room in the DTV we don't
|
||||
even try it and fail the load.
|
||||
|
||||
XXX We could track the minimum DTV slots allocated in
|
||||
all threads. */
|
||||
if (! RTLD_SINGLE_THREAD_P && imap->l_tls_modid > DTV_SURPLUS)
|
||||
_dl_signal_error (0, "dlopen", NULL, N_("\
|
||||
cannot load any more object with static TLS"));
|
||||
|
||||
now, but we can delay updating the DTV. */
|
||||
imap->l_need_tls_init = 0;
|
||||
#ifdef SHARED
|
||||
/* Update the slot information data for at least the
|
||||
|
||||
@@ -136,12 +136,6 @@ _dl_nothread_init_static_tls (struct link_map *map)
|
||||
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
|
||||
#endif
|
||||
|
||||
/* Fill in the DTV slot so that a later LD/GD access will find it. */
|
||||
dtv_t *dtv = THREAD_DTV ();
|
||||
assert (map->l_tls_modid <= dtv[-1].counter);
|
||||
dtv[map->l_tls_modid].pointer.val = dest;
|
||||
dtv[map->l_tls_modid].pointer.is_static = true;
|
||||
|
||||
/* Initialize the memory. */
|
||||
memset (__mempcpy (dest, map->l_tls_initimage, map->l_tls_initimage_size),
|
||||
'\0', map->l_tls_blocksize - map->l_tls_initimage_size);
|
||||
|
||||
+120
-85
@@ -347,6 +347,22 @@ _dl_get_tls_static_info (size_t *sizep, size_t *alignp)
|
||||
*alignp = GL(dl_tls_static_align);
|
||||
}
|
||||
|
||||
/* Derive the location of the pointer to the start of the original
|
||||
allocation (before alignment) from the pointer to the TCB. */
|
||||
static inline void **
|
||||
tcb_to_pointer_to_free_location (void *tcb)
|
||||
{
|
||||
#if TLS_TCB_AT_TP
|
||||
/* The TCB follows the TLS blocks, and the pointer to the front
|
||||
follows the TCB. */
|
||||
void **original_pointer_location = tcb + TLS_TCB_SIZE;
|
||||
#elif TLS_DTV_AT_TP
|
||||
/* The TCB comes first, preceded by the pre-TCB, and the pointer is
|
||||
before that. */
|
||||
void **original_pointer_location = tcb - TLS_PRE_TCB_SIZE - sizeof (void *);
|
||||
#endif
|
||||
return original_pointer_location;
|
||||
}
|
||||
|
||||
void *
|
||||
internal_function
|
||||
@@ -359,39 +375,50 @@ _dl_allocate_tls_storage (void)
|
||||
/* Memory layout is:
|
||||
[ TLS_PRE_TCB_SIZE ] [ TLS_TCB_SIZE ] [ TLS blocks ]
|
||||
^ This should be returned. */
|
||||
size += (TLS_PRE_TCB_SIZE + GL(dl_tls_static_align) - 1)
|
||||
& ~(GL(dl_tls_static_align) - 1);
|
||||
size += TLS_PRE_TCB_SIZE;
|
||||
#endif
|
||||
|
||||
/* Allocate a correctly aligned chunk of memory. */
|
||||
result = __libc_memalign (GL(dl_tls_static_align), size);
|
||||
if (__builtin_expect (result != NULL, 1))
|
||||
{
|
||||
/* Allocate the DTV. */
|
||||
void *allocated = result;
|
||||
/* Perform the allocation. Reserve space for the required alignment
|
||||
and the pointer to the original allocation. */
|
||||
size_t alignment = GL(dl_tls_static_align);
|
||||
void *allocated = malloc (size + alignment + sizeof (void *));
|
||||
if (__glibc_unlikely (allocated == NULL))
|
||||
return NULL;
|
||||
|
||||
/* Perform alignment and allocate the DTV. */
|
||||
#if TLS_TCB_AT_TP
|
||||
/* The TCB follows the TLS blocks. */
|
||||
result = (char *) result + size - TLS_TCB_SIZE;
|
||||
/* The TCB follows the TLS blocks, which determine the alignment.
|
||||
(TCB alignment requirements have been taken into account when
|
||||
calculating GL(dl_tls_static_align).) */
|
||||
void *aligned = (void *) roundup ((uintptr_t) allocated, alignment);
|
||||
result = aligned + size - TLS_TCB_SIZE;
|
||||
|
||||
/* Clear the TCB data structure. We can't ask the caller (i.e.
|
||||
libpthread) to do it, because we will initialize the DTV et al. */
|
||||
memset (result, '\0', TLS_TCB_SIZE);
|
||||
/* Clear the TCB data structure. We can't ask the caller (i.e.
|
||||
libpthread) to do it, because we will initialize the DTV et al. */
|
||||
memset (result, '\0', TLS_TCB_SIZE);
|
||||
#elif TLS_DTV_AT_TP
|
||||
result = (char *) result + size - GL(dl_tls_static_size);
|
||||
/* Pre-TCB and TCB come before the TLS blocks. The layout computed
|
||||
in _dl_determine_tlsoffset assumes that the TCB is aligned to the
|
||||
TLS block alignment, and not just the TLS blocks after it. This
|
||||
can leave an unused alignment gap between the TCB and the TLS
|
||||
blocks. */
|
||||
result = (void *) roundup
|
||||
(sizeof (void *) + TLS_PRE_TCB_SIZE + (uintptr_t) allocated,
|
||||
alignment);
|
||||
|
||||
/* Clear the TCB data structure and TLS_PRE_TCB_SIZE bytes before it.
|
||||
We can't ask the caller (i.e. libpthread) to do it, because we will
|
||||
initialize the DTV et al. */
|
||||
memset ((char *) result - TLS_PRE_TCB_SIZE, '\0',
|
||||
TLS_PRE_TCB_SIZE + TLS_TCB_SIZE);
|
||||
/* Clear the TCB data structure and TLS_PRE_TCB_SIZE bytes before
|
||||
it. We can't ask the caller (i.e. libpthread) to do it, because
|
||||
we will initialize the DTV et al. */
|
||||
memset (result - TLS_PRE_TCB_SIZE, '\0', TLS_PRE_TCB_SIZE + TLS_TCB_SIZE);
|
||||
#endif
|
||||
|
||||
result = allocate_dtv (result);
|
||||
if (result == NULL)
|
||||
free (allocated);
|
||||
}
|
||||
/* Record the value of the original pointer for later
|
||||
deallocation. */
|
||||
*tcb_to_pointer_to_free_location (result) = allocated;
|
||||
|
||||
result = allocate_dtv (result);
|
||||
if (result == NULL)
|
||||
free (allocated);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -493,17 +520,14 @@ _dl_allocate_tls_init (void *result)
|
||||
assert (listp->slotinfo[cnt].gen <= GL(dl_tls_generation));
|
||||
maxgen = MAX (maxgen, listp->slotinfo[cnt].gen);
|
||||
|
||||
dtv[map->l_tls_modid].pointer.val = TLS_DTV_UNALLOCATED;
|
||||
dtv[map->l_tls_modid].pointer.to_free = NULL;
|
||||
|
||||
if (map->l_tls_offset == NO_TLS_OFFSET
|
||||
|| map->l_tls_offset == FORCED_DYNAMIC_TLS_OFFSET)
|
||||
{
|
||||
/* For dynamically loaded modules we simply store
|
||||
the value indicating deferred allocation. */
|
||||
dtv[map->l_tls_modid].pointer.val = TLS_DTV_UNALLOCATED;
|
||||
dtv[map->l_tls_modid].pointer.is_static = false;
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
|
||||
assert (map->l_tls_modid == cnt);
|
||||
assert (map->l_tls_modid == total + cnt);
|
||||
assert (map->l_tls_blocksize >= map->l_tls_initimage_size);
|
||||
#if TLS_TCB_AT_TP
|
||||
assert ((size_t) map->l_tls_offset >= map->l_tls_blocksize);
|
||||
@@ -515,8 +539,6 @@ _dl_allocate_tls_init (void *result)
|
||||
#endif
|
||||
|
||||
/* Copy the initialization image and clear the BSS part. */
|
||||
dtv[map->l_tls_modid].pointer.val = dest;
|
||||
dtv[map->l_tls_modid].pointer.is_static = true;
|
||||
memset (__mempcpy (dest, map->l_tls_initimage,
|
||||
map->l_tls_initimage_size), '\0',
|
||||
map->l_tls_blocksize - map->l_tls_initimage_size);
|
||||
@@ -556,26 +578,14 @@ _dl_deallocate_tls (void *tcb, bool dealloc_tcb)
|
||||
|
||||
/* We need to free the memory allocated for non-static TLS. */
|
||||
for (size_t cnt = 0; cnt < dtv[-1].counter; ++cnt)
|
||||
if (! dtv[1 + cnt].pointer.is_static
|
||||
&& dtv[1 + cnt].pointer.val != TLS_DTV_UNALLOCATED)
|
||||
free (dtv[1 + cnt].pointer.val);
|
||||
free (dtv[1 + cnt].pointer.to_free);
|
||||
|
||||
/* The array starts with dtv[-1]. */
|
||||
if (dtv != GL(dl_initial_dtv))
|
||||
free (dtv - 1);
|
||||
|
||||
if (dealloc_tcb)
|
||||
{
|
||||
#if TLS_TCB_AT_TP
|
||||
/* The TCB follows the TLS blocks. Back up to free the whole block. */
|
||||
tcb -= GL(dl_tls_static_size) - TLS_TCB_SIZE;
|
||||
#elif TLS_DTV_AT_TP
|
||||
/* Back up the TLS_PRE_TCB_SIZE bytes. */
|
||||
tcb -= (TLS_PRE_TCB_SIZE + GL(dl_tls_static_align) - 1)
|
||||
& ~(GL(dl_tls_static_align) - 1);
|
||||
#endif
|
||||
free (tcb);
|
||||
}
|
||||
free (*tcb_to_pointer_to_free_location (tcb));
|
||||
}
|
||||
rtld_hidden_def (_dl_deallocate_tls)
|
||||
|
||||
@@ -599,21 +609,49 @@ rtld_hidden_def (_dl_deallocate_tls)
|
||||
# define GET_ADDR_OFFSET ti->ti_offset
|
||||
# endif
|
||||
|
||||
/* Allocate one DTV entry. */
|
||||
static struct dtv_pointer
|
||||
allocate_dtv_entry (size_t alignment, size_t size)
|
||||
{
|
||||
if (powerof2 (alignment) && alignment <= _Alignof (long double))
|
||||
{
|
||||
/* The alignment is supported by malloc. */
|
||||
void *ptr = malloc (size);
|
||||
return (struct dtv_pointer) { ptr, ptr };
|
||||
}
|
||||
|
||||
static void *
|
||||
/* Emulate memalign to by manually aligning a pointer returned by
|
||||
malloc. First compute the size with an overflow check. */
|
||||
size_t alloc_size = size + alignment;
|
||||
if (alloc_size < size)
|
||||
return (struct dtv_pointer) {};
|
||||
|
||||
/* Perform the allocation. This is the pointer we need to free
|
||||
later. */
|
||||
void *start = malloc (alloc_size);
|
||||
if (start == NULL)
|
||||
return (struct dtv_pointer) {};
|
||||
|
||||
/* Find the aligned position within the larger allocation. */
|
||||
void *aligned = (void *) roundup ((uintptr_t) start, alignment);
|
||||
|
||||
return (struct dtv_pointer) { .val = aligned, .to_free = start };
|
||||
}
|
||||
|
||||
static struct dtv_pointer
|
||||
allocate_and_init (struct link_map *map)
|
||||
{
|
||||
void *newp;
|
||||
|
||||
newp = __libc_memalign (map->l_tls_align, map->l_tls_blocksize);
|
||||
if (newp == NULL)
|
||||
struct dtv_pointer result = allocate_dtv_entry
|
||||
(map->l_tls_align, map->l_tls_blocksize);
|
||||
if (result.val == NULL)
|
||||
oom ();
|
||||
|
||||
/* Initialize the memory. */
|
||||
memset (__mempcpy (newp, map->l_tls_initimage, map->l_tls_initimage_size),
|
||||
memset (__mempcpy (result.val, map->l_tls_initimage,
|
||||
map->l_tls_initimage_size),
|
||||
'\0', map->l_tls_blocksize - map->l_tls_initimage_size);
|
||||
|
||||
return newp;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -679,13 +717,13 @@ _dl_update_slotinfo (unsigned long int req_modid)
|
||||
struct link_map *map = listp->slotinfo[cnt].map;
|
||||
if (map == NULL)
|
||||
{
|
||||
/* If this modid was used at some point the memory
|
||||
might still be allocated. */
|
||||
if (! dtv[total + cnt].pointer.is_static
|
||||
&& dtv[total + cnt].pointer.val != TLS_DTV_UNALLOCATED)
|
||||
if (dtv[-1].counter >= total + cnt)
|
||||
{
|
||||
free (dtv[total + cnt].pointer.val);
|
||||
/* If this modid was used at some point the memory
|
||||
might still be allocated. */
|
||||
free (dtv[total + cnt].pointer.to_free);
|
||||
dtv[total + cnt].pointer.val = TLS_DTV_UNALLOCATED;
|
||||
dtv[total + cnt].pointer.to_free = NULL;
|
||||
}
|
||||
|
||||
continue;
|
||||
@@ -710,18 +748,9 @@ _dl_update_slotinfo (unsigned long int req_modid)
|
||||
dtv entry free it. */
|
||||
/* XXX Ideally we will at some point create a memory
|
||||
pool. */
|
||||
if (! dtv[modid].pointer.is_static
|
||||
&& dtv[modid].pointer.val != TLS_DTV_UNALLOCATED)
|
||||
/* Note that free is called for NULL is well. We
|
||||
deallocate even if it is this dtv entry we are
|
||||
supposed to load. The reason is that we call
|
||||
memalign and not malloc. */
|
||||
free (dtv[modid].pointer.val);
|
||||
|
||||
/* This module is loaded dynamically- We defer memory
|
||||
allocation. */
|
||||
dtv[modid].pointer.is_static = false;
|
||||
free (dtv[modid].pointer.to_free);
|
||||
dtv[modid].pointer.val = TLS_DTV_UNALLOCATED;
|
||||
dtv[modid].pointer.to_free = NULL;
|
||||
|
||||
if (modid == req_modid)
|
||||
the_map = map;
|
||||
@@ -759,13 +788,12 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map)
|
||||
the_map = listp->slotinfo[idx].map;
|
||||
}
|
||||
|
||||
again:
|
||||
/* Make sure that, if a dlopen running in parallel forces the
|
||||
variable into static storage, we'll wait until the address in the
|
||||
static TLS block is set up, and use that. If we're undecided
|
||||
yet, make sure we make the decision holding the lock as well. */
|
||||
if (__builtin_expect (the_map->l_tls_offset
|
||||
!= FORCED_DYNAMIC_TLS_OFFSET, 0))
|
||||
if (__glibc_unlikely (the_map->l_tls_offset
|
||||
!= FORCED_DYNAMIC_TLS_OFFSET))
|
||||
{
|
||||
__rtld_lock_lock_recursive (GL(dl_load_lock));
|
||||
if (__glibc_likely (the_map->l_tls_offset == NO_TLS_OFFSET))
|
||||
@@ -773,24 +801,31 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map)
|
||||
the_map->l_tls_offset = FORCED_DYNAMIC_TLS_OFFSET;
|
||||
__rtld_lock_unlock_recursive (GL(dl_load_lock));
|
||||
}
|
||||
else
|
||||
else if (__glibc_likely (the_map->l_tls_offset
|
||||
!= FORCED_DYNAMIC_TLS_OFFSET))
|
||||
{
|
||||
#if TLS_TCB_AT_TP
|
||||
void *p = (char *) THREAD_SELF - the_map->l_tls_offset;
|
||||
#elif TLS_DTV_AT_TP
|
||||
void *p = (char *) THREAD_SELF + the_map->l_tls_offset + TLS_PRE_TCB_SIZE;
|
||||
#else
|
||||
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
|
||||
#endif
|
||||
__rtld_lock_unlock_recursive (GL(dl_load_lock));
|
||||
if (__builtin_expect (the_map->l_tls_offset
|
||||
!= FORCED_DYNAMIC_TLS_OFFSET, 1))
|
||||
{
|
||||
void *p = dtv[GET_ADDR_MODULE].pointer.val;
|
||||
if (__glibc_unlikely (p == TLS_DTV_UNALLOCATED))
|
||||
goto again;
|
||||
|
||||
return (char *) p + GET_ADDR_OFFSET;
|
||||
}
|
||||
dtv[GET_ADDR_MODULE].pointer.to_free = NULL;
|
||||
dtv[GET_ADDR_MODULE].pointer.val = p;
|
||||
|
||||
return (char *) p + GET_ADDR_OFFSET;
|
||||
}
|
||||
else
|
||||
__rtld_lock_unlock_recursive (GL(dl_load_lock));
|
||||
}
|
||||
void *p = dtv[GET_ADDR_MODULE].pointer.val = allocate_and_init (the_map);
|
||||
dtv[GET_ADDR_MODULE].pointer.is_static = false;
|
||||
struct dtv_pointer result = allocate_and_init (the_map);
|
||||
dtv[GET_ADDR_MODULE].pointer = result;
|
||||
assert (result.to_free != NULL);
|
||||
|
||||
return (char *) p + GET_ADDR_OFFSET;
|
||||
return (char *) result.val + GET_ADDR_OFFSET;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -167,11 +167,11 @@ makesymlink (src, dest)
|
||||
const char *src;
|
||||
const char *dest;
|
||||
{
|
||||
struct stat stats;
|
||||
struct stat64 stats;
|
||||
const char *error;
|
||||
|
||||
/* Destination must not be a directory. */
|
||||
if (lstat (dest, &stats) == 0)
|
||||
if (lstat64 (dest, &stats) == 0)
|
||||
{
|
||||
if (S_ISDIR (stats.st_mode))
|
||||
{
|
||||
|
||||
+2
-2
@@ -42,7 +42,7 @@ eq_tlsdesc (void *p, void *q)
|
||||
return tdp->tlsinfo.ti_offset == tdq->tlsinfo.ti_offset;
|
||||
}
|
||||
|
||||
inline static int
|
||||
inline static size_t
|
||||
map_generation (struct link_map *map)
|
||||
{
|
||||
size_t idx = map->l_tls_modid;
|
||||
@@ -58,7 +58,7 @@ map_generation (struct link_map *map)
|
||||
we can assume that, if the generation count is zero, we
|
||||
still haven't determined the generation count for this
|
||||
module. */
|
||||
if (listp->slotinfo[idx].gen)
|
||||
if (listp->slotinfo[idx].map == map && listp->slotinfo[idx].gen)
|
||||
return listp->slotinfo[idx].gen;
|
||||
else
|
||||
break;
|
||||
|
||||
@@ -138,6 +138,21 @@
|
||||
# define weak_extern(symbol) _weak_extern (weak symbol)
|
||||
# define _weak_extern(expr) _Pragma (#expr)
|
||||
|
||||
/* In shared builds, the expression call_function_static_weak
|
||||
(FUNCTION-SYMBOL, ARGUMENTS) invokes FUNCTION-SYMBOL (an
|
||||
identifier) unconditionally, with the (potentially empty) argument
|
||||
list ARGUMENTS. In static builds, if FUNCTION-SYMBOL has a
|
||||
definition, the function is invoked as before; if FUNCTION-SYMBOL
|
||||
is NULL, no call is performed. */
|
||||
# ifdef SHARED
|
||||
# define call_function_static_weak(func, ...) func (__VA_ARGS__)
|
||||
# else /* !SHARED */
|
||||
# define call_function_static_weak(func, ...) \
|
||||
({ \
|
||||
extern __typeof__ (func) func weak_function; \
|
||||
(func != NULL ? func (__VA_ARGS__) : (void)0); \
|
||||
})
|
||||
# endif
|
||||
|
||||
#else /* __ASSEMBLER__ */
|
||||
|
||||
|
||||
+3
-1
@@ -45,7 +45,7 @@ export LC_ALL
|
||||
tmp=${objpfx}io
|
||||
tmpdir=$tmp/ftwtest.d
|
||||
|
||||
trap 'chmod -fR a+x $tmpdir; rm -fr $tmpdir $testout' 1 2 3 15
|
||||
trap 'chmod -fR a+x $tmpdir; rm -fr $tmpdir $testout' 0 1 2 3 15
|
||||
|
||||
if test -d $tmpdir; then
|
||||
chmod -fR a+x $tmpdir
|
||||
@@ -296,4 +296,6 @@ rm $testout
|
||||
|
||||
rm -fr $tmpdir
|
||||
|
||||
trap '' 0
|
||||
|
||||
exit 0
|
||||
|
||||
+7
-1
@@ -95,8 +95,11 @@ _IO_wstr_overflow (fp, c)
|
||||
wchar_t *old_buf = fp->_wide_data->_IO_buf_base;
|
||||
size_t old_wblen = _IO_wblen (fp);
|
||||
_IO_size_t new_size = 2 * old_wblen + 100;
|
||||
if (new_size < old_wblen)
|
||||
|
||||
if (__glibc_unlikely (new_size < old_wblen)
|
||||
|| __glibc_unlikely (new_size > SIZE_MAX / sizeof (wchar_t)))
|
||||
return EOF;
|
||||
|
||||
new_buf
|
||||
= (wchar_t *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (new_size
|
||||
* sizeof (wchar_t));
|
||||
@@ -186,6 +189,9 @@ enlarge_userbuf (_IO_FILE *fp, _IO_off64_t offset, int reading)
|
||||
return 1;
|
||||
|
||||
_IO_size_t newsize = offset + 100;
|
||||
if (__glibc_unlikely (newsize > SIZE_MAX / sizeof (wchar_t)))
|
||||
return 1;
|
||||
|
||||
wchar_t *oldbuf = wd->_IO_buf_base;
|
||||
wchar_t *newbuf
|
||||
= (wchar_t *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (newsize
|
||||
|
||||
+32
-1
@@ -27,7 +27,16 @@ headers := $(dist-headers) obstack.h mcheck.h
|
||||
tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \
|
||||
tst-mallocstate tst-mcheck tst-mallocfork tst-trim1 \
|
||||
tst-malloc-usable tst-realloc tst-posix_memalign \
|
||||
tst-pvalloc tst-memalign tst-mallopt
|
||||
tst-pvalloc tst-memalign tst-mallopt tst-malloc-fork-deadlock \
|
||||
tst-interpose-nothread \
|
||||
tst-interpose-thread \
|
||||
tst-interpose-static-nothread \
|
||||
tst-interpose-static-thread \
|
||||
|
||||
tests-static := \
|
||||
tst-interpose-static-nothread \
|
||||
tst-interpose-static-thread \
|
||||
|
||||
test-srcs = tst-mtrace
|
||||
|
||||
routines = malloc morecore mcheck mtrace obstack
|
||||
@@ -39,9 +48,20 @@ non-lib.a := libmcheck.a
|
||||
extra-libs = libmemusage
|
||||
extra-libs-others = $(extra-libs)
|
||||
|
||||
# Helper objects for some tests.
|
||||
extra-tests-objs += \
|
||||
tst-interpose-aux-nothread.o \
|
||||
tst-interpose-aux-thread.o \
|
||||
|
||||
test-extras = \
|
||||
tst-interpose-aux-nothread \
|
||||
tst-interpose-aux-thread \
|
||||
|
||||
libmemusage-routines = memusage
|
||||
libmemusage-inhibit-o = $(filter-out .os,$(object-suffixes))
|
||||
|
||||
$(objpfx)tst-malloc-fork-deadlock: $(shared-thread-library)
|
||||
|
||||
# These should be removed by `make clean'.
|
||||
extra-objs = mcheck-init.o libmcheck.a
|
||||
|
||||
@@ -156,3 +176,14 @@ $(objpfx)libmemusage.so: $(libdl)
|
||||
|
||||
# Extra dependencies
|
||||
$(foreach o,$(all-object-suffixes),$(objpfx)malloc$(o)): arena.c hooks.c
|
||||
|
||||
# Compile the tests with a flag which suppresses the mallopt call in
|
||||
# the test skeleton.
|
||||
$(tests:%=$(objpfx)%.o): CPPFLAGS += -DTEST_NO_MALLOPT
|
||||
|
||||
$(objpfx)tst-interpose-nothread: $(objpfx)tst-interpose-aux-nothread.o
|
||||
$(objpfx)tst-interpose-thread: \
|
||||
$(objpfx)tst-interpose-aux-thread.o $(shared-thread-library)
|
||||
$(objpfx)tst-interpose-static-nothread: $(objpfx)tst-interpose-aux-nothread.o
|
||||
$(objpfx)tst-interpose-static-thread: \
|
||||
$(objpfx)tst-interpose-aux-thread.o $(static-thread-library)
|
||||
|
||||
+142
-72
@@ -64,13 +64,32 @@ extern int sanity_check_heap_info_alignment[(sizeof (heap_info)
|
||||
+ 2 * SIZE_SZ) % MALLOC_ALIGNMENT
|
||||
? -1 : 1];
|
||||
|
||||
/* Thread specific data */
|
||||
/* Thread specific data. */
|
||||
|
||||
static tsd_key_t arena_key;
|
||||
static mutex_t list_lock = MUTEX_INITIALIZER;
|
||||
static __thread mstate thread_arena attribute_tls_model_ie;
|
||||
|
||||
/* Arena free list. free_list_lock synchronizes access to the
|
||||
free_list variable below, and the next_free and attached_threads
|
||||
members of struct malloc_state objects. No other locks must be
|
||||
acquired after free_list_lock has been acquired. */
|
||||
|
||||
static mutex_t free_list_lock = _LIBC_LOCK_INITIALIZER;
|
||||
static size_t narenas = 1;
|
||||
static mstate free_list;
|
||||
|
||||
/* list_lock prevents concurrent writes to the next member of struct
|
||||
malloc_state objects.
|
||||
|
||||
Read access to the next member is supposed to synchronize with the
|
||||
atomic_write_barrier and the write to the next member in
|
||||
_int_new_arena. This suffers from data races; see the FIXME
|
||||
comments in _int_new_arena and reused_arena.
|
||||
|
||||
list_lock also prevents concurrent forks. When list_lock is
|
||||
acquired, no arena lock must be acquired, but it is permitted to
|
||||
acquire arena locks after list_lock. */
|
||||
static mutex_t list_lock = _LIBC_LOCK_INITIALIZER;
|
||||
|
||||
/* Mapped memory in non-main arenas (reliable only for NO_THREADS). */
|
||||
static unsigned long arena_mem;
|
||||
|
||||
@@ -89,15 +108,10 @@ int __malloc_initialized = -1;
|
||||
in the new arena. */
|
||||
|
||||
#define arena_get(ptr, size) do { \
|
||||
arena_lookup (ptr); \
|
||||
ptr = thread_arena; \
|
||||
arena_lock (ptr, size); \
|
||||
} while (0)
|
||||
|
||||
#define arena_lookup(ptr) do { \
|
||||
void *vptr = NULL; \
|
||||
ptr = (mstate) tsd_getspecific (arena_key, vptr); \
|
||||
} while (0)
|
||||
|
||||
#define arena_lock(ptr, size) do { \
|
||||
if (ptr) \
|
||||
(void) mutex_lock (&ptr->mutex); \
|
||||
@@ -123,10 +137,6 @@ static void *(*save_malloc_hook)(size_t __size, const void *);
|
||||
static void (*save_free_hook) (void *__ptr, const void *);
|
||||
static void *save_arena;
|
||||
|
||||
# ifdef ATFORK_MEM
|
||||
ATFORK_MEM;
|
||||
# endif
|
||||
|
||||
/* Magic value for the thread-specific arena pointer when
|
||||
malloc_atfork() is in use. */
|
||||
|
||||
@@ -138,11 +148,9 @@ ATFORK_MEM;
|
||||
static void *
|
||||
malloc_atfork (size_t sz, const void *caller)
|
||||
{
|
||||
void *vptr = NULL;
|
||||
void *victim;
|
||||
|
||||
tsd_getspecific (arena_key, vptr);
|
||||
if (vptr == ATFORK_ARENA_PTR)
|
||||
if (thread_arena == ATFORK_ARENA_PTR)
|
||||
{
|
||||
/* We are the only thread that may allocate at all. */
|
||||
if (save_malloc_hook != malloc_check)
|
||||
@@ -172,7 +180,6 @@ malloc_atfork (size_t sz, const void *caller)
|
||||
static void
|
||||
free_atfork (void *mem, const void *caller)
|
||||
{
|
||||
void *vptr = NULL;
|
||||
mstate ar_ptr;
|
||||
mchunkptr p; /* chunk corresponding to mem */
|
||||
|
||||
@@ -188,33 +195,34 @@ free_atfork (void *mem, const void *caller)
|
||||
}
|
||||
|
||||
ar_ptr = arena_for_chunk (p);
|
||||
tsd_getspecific (arena_key, vptr);
|
||||
_int_free (ar_ptr, p, vptr == ATFORK_ARENA_PTR);
|
||||
_int_free (ar_ptr, p, thread_arena == ATFORK_ARENA_PTR);
|
||||
}
|
||||
|
||||
|
||||
/* Counter for number of times the list is locked by the same thread. */
|
||||
static unsigned int atfork_recursive_cntr;
|
||||
|
||||
/* The following two functions are registered via thread_atfork() to
|
||||
make sure that the mutexes remain in a consistent state in the
|
||||
fork()ed version of a thread. Also adapt the malloc and free hooks
|
||||
temporarily, because the `atfork' handler mechanism may use
|
||||
malloc/free internally (e.g. in LinuxThreads). */
|
||||
/* The following three functions are called around fork from a
|
||||
multi-threaded process. We do not use the general fork handler
|
||||
mechanism to make sure that our handlers are the last ones being
|
||||
called, so that other fork handlers can use the malloc
|
||||
subsystem. */
|
||||
|
||||
static void
|
||||
ptmalloc_lock_all (void)
|
||||
void
|
||||
internal_function
|
||||
__malloc_fork_lock_parent (void)
|
||||
{
|
||||
mstate ar_ptr;
|
||||
|
||||
if (__malloc_initialized < 1)
|
||||
return;
|
||||
|
||||
/* We do not acquire free_list_lock here because we completely
|
||||
reconstruct free_list in __malloc_fork_unlock_child. */
|
||||
|
||||
if (mutex_trylock (&list_lock))
|
||||
{
|
||||
void *my_arena;
|
||||
tsd_getspecific (arena_key, my_arena);
|
||||
if (my_arena == ATFORK_ARENA_PTR)
|
||||
if (thread_arena == ATFORK_ARENA_PTR)
|
||||
/* This is the same thread which already locks the global list.
|
||||
Just bump the counter. */
|
||||
goto out;
|
||||
@@ -233,15 +241,19 @@ ptmalloc_lock_all (void)
|
||||
save_free_hook = __free_hook;
|
||||
__malloc_hook = malloc_atfork;
|
||||
__free_hook = free_atfork;
|
||||
/* Only the current thread may perform malloc/free calls now. */
|
||||
tsd_getspecific (arena_key, save_arena);
|
||||
tsd_setspecific (arena_key, ATFORK_ARENA_PTR);
|
||||
/* Only the current thread may perform malloc/free calls now.
|
||||
save_arena will be reattached to the current thread, in
|
||||
__malloc_fork_lock_parent, so save_arena->attached_threads is not
|
||||
updated. */
|
||||
save_arena = thread_arena;
|
||||
thread_arena = ATFORK_ARENA_PTR;
|
||||
out:
|
||||
++atfork_recursive_cntr;
|
||||
}
|
||||
|
||||
static void
|
||||
ptmalloc_unlock_all (void)
|
||||
void
|
||||
internal_function
|
||||
__malloc_fork_unlock_parent (void)
|
||||
{
|
||||
mstate ar_ptr;
|
||||
|
||||
@@ -251,7 +263,10 @@ ptmalloc_unlock_all (void)
|
||||
if (--atfork_recursive_cntr != 0)
|
||||
return;
|
||||
|
||||
tsd_setspecific (arena_key, save_arena);
|
||||
/* Replace ATFORK_ARENA_PTR with save_arena.
|
||||
save_arena->attached_threads was not changed in
|
||||
__malloc_fork_lock_parent and is still correct. */
|
||||
thread_arena = save_arena;
|
||||
__malloc_hook = save_malloc_hook;
|
||||
__free_hook = save_free_hook;
|
||||
for (ar_ptr = &main_arena;; )
|
||||
@@ -264,30 +279,32 @@ ptmalloc_unlock_all (void)
|
||||
(void) mutex_unlock (&list_lock);
|
||||
}
|
||||
|
||||
# ifdef __linux__
|
||||
|
||||
/* In NPTL, unlocking a mutex in the child process after a
|
||||
fork() is currently unsafe, whereas re-initializing it is safe and
|
||||
does not leak resources. Therefore, a special atfork handler is
|
||||
installed for the child. */
|
||||
|
||||
static void
|
||||
ptmalloc_unlock_all2 (void)
|
||||
void
|
||||
internal_function
|
||||
__malloc_fork_unlock_child (void)
|
||||
{
|
||||
mstate ar_ptr;
|
||||
|
||||
if (__malloc_initialized < 1)
|
||||
return;
|
||||
|
||||
tsd_setspecific (arena_key, save_arena);
|
||||
thread_arena = save_arena;
|
||||
__malloc_hook = save_malloc_hook;
|
||||
__free_hook = save_free_hook;
|
||||
|
||||
/* Push all arenas to the free list, except save_arena, which is
|
||||
attached to the current thread. */
|
||||
mutex_init (&free_list_lock);
|
||||
if (save_arena != NULL)
|
||||
((mstate) save_arena)->attached_threads = 1;
|
||||
free_list = NULL;
|
||||
for (ar_ptr = &main_arena;; )
|
||||
{
|
||||
mutex_init (&ar_ptr->mutex);
|
||||
if (ar_ptr != save_arena)
|
||||
{
|
||||
/* This arena is no longer attached to any thread. */
|
||||
ar_ptr->attached_threads = 0;
|
||||
ar_ptr->next_free = free_list;
|
||||
free_list = ar_ptr;
|
||||
}
|
||||
@@ -295,6 +312,7 @@ ptmalloc_unlock_all2 (void)
|
||||
if (ar_ptr == &main_arena)
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_init (&list_lock);
|
||||
atfork_recursive_cntr = 0;
|
||||
}
|
||||
@@ -302,8 +320,8 @@ ptmalloc_unlock_all2 (void)
|
||||
# else
|
||||
|
||||
# define ptmalloc_unlock_all2 ptmalloc_unlock_all
|
||||
# endif
|
||||
#endif /* !NO_THREADS */
|
||||
#endif
|
||||
|
||||
|
||||
/* Initialization routine. */
|
||||
#include <string.h>
|
||||
@@ -372,9 +390,7 @@ ptmalloc_init (void)
|
||||
__morecore = __failing_morecore;
|
||||
#endif
|
||||
|
||||
tsd_key_create (&arena_key, NULL);
|
||||
tsd_setspecific (arena_key, (void *) &main_arena);
|
||||
thread_atfork (ptmalloc_lock_all, ptmalloc_unlock_all, ptmalloc_unlock_all2);
|
||||
thread_arena = &main_arena;
|
||||
const char *s = NULL;
|
||||
if (__glibc_likely (_environ != NULL))
|
||||
{
|
||||
@@ -449,14 +465,6 @@ ptmalloc_init (void)
|
||||
__malloc_initialized = 1;
|
||||
}
|
||||
|
||||
/* There are platforms (e.g. Hurd) with a link-time hook mechanism. */
|
||||
#ifdef thread_atfork_static
|
||||
thread_atfork_static (ptmalloc_lock_all, ptmalloc_unlock_all, \
|
||||
ptmalloc_unlock_all2)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Managing heaps and arenas (for concurrent threads) */
|
||||
|
||||
#if MALLOC_DEBUG > 1
|
||||
@@ -714,6 +722,22 @@ heap_trim (heap_info *heap, size_t pad)
|
||||
|
||||
/* Create a new arena with initial size "size". */
|
||||
|
||||
/* If REPLACED_ARENA is not NULL, detach it from this thread. Must be
|
||||
called while free_list_lock is held. */
|
||||
static void
|
||||
detach_arena (mstate replaced_arena)
|
||||
{
|
||||
if (replaced_arena != NULL)
|
||||
{
|
||||
assert (replaced_arena->attached_threads > 0);
|
||||
/* The current implementation only detaches from main_arena in
|
||||
case of allocation failure. This means that it is likely not
|
||||
beneficial to put the arena on free_list even if the
|
||||
reference count reaches zero. */
|
||||
--replaced_arena->attached_threads;
|
||||
}
|
||||
}
|
||||
|
||||
static mstate
|
||||
_int_new_arena (size_t size)
|
||||
{
|
||||
@@ -735,6 +759,7 @@ _int_new_arena (size_t size)
|
||||
}
|
||||
a = h->ar_ptr = (mstate) (h + 1);
|
||||
malloc_init_state (a);
|
||||
a->attached_threads = 1;
|
||||
/*a->next = NULL;*/
|
||||
a->system_mem = a->max_system_mem = h->size;
|
||||
arena_mem += h->size;
|
||||
@@ -748,19 +773,38 @@ _int_new_arena (size_t size)
|
||||
set_head (top (a), (((char *) h + h->size) - ptr) | PREV_INUSE);
|
||||
|
||||
LIBC_PROBE (memory_arena_new, 2, a, size);
|
||||
tsd_setspecific (arena_key, (void *) a);
|
||||
mstate replaced_arena = thread_arena;
|
||||
thread_arena = a;
|
||||
mutex_init (&a->mutex);
|
||||
(void) mutex_lock (&a->mutex);
|
||||
|
||||
(void) mutex_lock (&list_lock);
|
||||
|
||||
/* Add the new arena to the global list. */
|
||||
a->next = main_arena.next;
|
||||
/* FIXME: The barrier is an attempt to synchronize with read access
|
||||
in reused_arena, which does not acquire list_lock while
|
||||
traversing the list. */
|
||||
atomic_write_barrier ();
|
||||
main_arena.next = a;
|
||||
|
||||
(void) mutex_unlock (&list_lock);
|
||||
|
||||
(void) mutex_lock (&free_list_lock);
|
||||
detach_arena (replaced_arena);
|
||||
(void) mutex_unlock (&free_list_lock);
|
||||
|
||||
/* Lock this arena. NB: Another thread may have been attached to
|
||||
this arena because the arena is now accessible from the
|
||||
main_arena.next list and could have been picked by reused_arena.
|
||||
This can only happen for the last arena created (before the arena
|
||||
limit is reached). At this point, some arena has to be attached
|
||||
to two threads. We could acquire the arena lock before list_lock
|
||||
to make it less likely that reused_arena picks this new arena,
|
||||
but this could result in a deadlock with
|
||||
__malloc_fork_lock_parent. */
|
||||
|
||||
(void) mutex_lock (&a->mutex);
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
@@ -768,20 +812,30 @@ _int_new_arena (size_t size)
|
||||
static mstate
|
||||
get_free_list (void)
|
||||
{
|
||||
mstate replaced_arena = thread_arena;
|
||||
mstate result = free_list;
|
||||
if (result != NULL)
|
||||
{
|
||||
(void) mutex_lock (&list_lock);
|
||||
(void) mutex_lock (&free_list_lock);
|
||||
result = free_list;
|
||||
if (result != NULL)
|
||||
free_list = result->next_free;
|
||||
(void) mutex_unlock (&list_lock);
|
||||
{
|
||||
free_list = result->next_free;
|
||||
|
||||
/* Arenas on the free list are not attached to any thread. */
|
||||
assert (result->attached_threads == 0);
|
||||
/* But the arena will now be attached to this thread. */
|
||||
result->attached_threads = 1;
|
||||
|
||||
detach_arena (replaced_arena);
|
||||
}
|
||||
(void) mutex_unlock (&free_list_lock);
|
||||
|
||||
if (result != NULL)
|
||||
{
|
||||
LIBC_PROBE (memory_arena_reuse_free_list, 1, result);
|
||||
(void) mutex_lock (&result->mutex);
|
||||
tsd_setspecific (arena_key, (void *) result);
|
||||
thread_arena = result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -795,6 +849,7 @@ static mstate
|
||||
reused_arena (mstate avoid_arena)
|
||||
{
|
||||
mstate result;
|
||||
/* FIXME: Access to next_to_use suffers from data races. */
|
||||
static mstate next_to_use;
|
||||
if (next_to_use == NULL)
|
||||
next_to_use = &main_arena;
|
||||
@@ -805,6 +860,7 @@ reused_arena (mstate avoid_arena)
|
||||
if (!mutex_trylock (&result->mutex))
|
||||
goto out;
|
||||
|
||||
/* FIXME: This is a data race, see _int_new_arena. */
|
||||
result = result->next;
|
||||
}
|
||||
while (result != next_to_use);
|
||||
@@ -819,8 +875,17 @@ reused_arena (mstate avoid_arena)
|
||||
(void) mutex_lock (&result->mutex);
|
||||
|
||||
out:
|
||||
{
|
||||
/* Update the arena thread attachment counters. */
|
||||
mstate replaced_arena = thread_arena;
|
||||
(void) mutex_lock (&free_list_lock);
|
||||
detach_arena (replaced_arena);
|
||||
++result->attached_threads;
|
||||
(void) mutex_unlock (&free_list_lock);
|
||||
}
|
||||
|
||||
LIBC_PROBE (memory_arena_reuse, 2, result, avoid_arena);
|
||||
tsd_setspecific (arena_key, (void *) result);
|
||||
thread_arena = result;
|
||||
next_to_use = result->next;
|
||||
|
||||
return result;
|
||||
@@ -905,16 +970,21 @@ arena_get_retry (mstate ar_ptr, size_t bytes)
|
||||
static void __attribute__ ((section ("__libc_thread_freeres_fn")))
|
||||
arena_thread_freeres (void)
|
||||
{
|
||||
void *vptr = NULL;
|
||||
mstate a = tsd_getspecific (arena_key, vptr);
|
||||
tsd_setspecific (arena_key, NULL);
|
||||
mstate a = thread_arena;
|
||||
thread_arena = NULL;
|
||||
|
||||
if (a != NULL)
|
||||
{
|
||||
(void) mutex_lock (&list_lock);
|
||||
a->next_free = free_list;
|
||||
free_list = a;
|
||||
(void) mutex_unlock (&list_lock);
|
||||
(void) mutex_lock (&free_list_lock);
|
||||
/* If this was the last attached thread for this arena, put the
|
||||
arena on the free list. */
|
||||
assert (a->attached_threads > 0);
|
||||
if (--a->attached_threads == 0)
|
||||
{
|
||||
a->next_free = free_list;
|
||||
free_list = a;
|
||||
}
|
||||
(void) mutex_unlock (&free_list_lock);
|
||||
}
|
||||
}
|
||||
text_set_element (__libc_thread_subfreeres, arena_thread_freeres);
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/* Internal declarations for malloc, for use within libc.
|
||||
Copyright (C) 2016 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef _MALLOC_PRIVATE_H
|
||||
#define _MALLOC_PRIVATE_H
|
||||
|
||||
/* Called in the parent process before a fork. */
|
||||
void __malloc_fork_lock_parent (void) internal_function attribute_hidden;
|
||||
|
||||
/* Called in the parent process after a fork. */
|
||||
void __malloc_fork_unlock_parent (void) internal_function attribute_hidden;
|
||||
|
||||
/* Called in the child process after a fork. */
|
||||
void __malloc_fork_unlock_child (void) internal_function attribute_hidden;
|
||||
|
||||
|
||||
#endif /* _MALLOC_PRIVATE_H */
|
||||
+15
-5
@@ -241,6 +241,10 @@
|
||||
/* For MIN, MAX, powerof2. */
|
||||
#include <sys/param.h>
|
||||
|
||||
/* For ALIGN_UP et. al. */
|
||||
#include <libc-internal.h>
|
||||
|
||||
#include <malloc/malloc-internal.h>
|
||||
|
||||
/*
|
||||
Debugging:
|
||||
@@ -1696,9 +1700,15 @@ struct malloc_state
|
||||
/* Linked list */
|
||||
struct malloc_state *next;
|
||||
|
||||
/* Linked list for free arenas. */
|
||||
/* Linked list for free arenas. Access to this field is serialized
|
||||
by free_list_lock in arena.c. */
|
||||
struct malloc_state *next_free;
|
||||
|
||||
/* Number of threads attached to this arena. 0 if the arena is on
|
||||
the free list. Access to this field is serialized by
|
||||
free_list_lock in arena.c. */
|
||||
INTERNAL_SIZE_T attached_threads;
|
||||
|
||||
/* Memory allocated from the system in this arena. */
|
||||
INTERNAL_SIZE_T system_mem;
|
||||
INTERNAL_SIZE_T max_system_mem;
|
||||
@@ -1741,8 +1751,9 @@ struct malloc_par
|
||||
|
||||
static struct malloc_state main_arena =
|
||||
{
|
||||
.mutex = MUTEX_INITIALIZER,
|
||||
.next = &main_arena
|
||||
.mutex = _LIBC_LOCK_INITIALIZER,
|
||||
.next = &main_arena,
|
||||
.attached_threads = 1
|
||||
};
|
||||
|
||||
/* There is only one instance of the malloc parameters. */
|
||||
@@ -2883,9 +2894,8 @@ __libc_malloc (size_t bytes)
|
||||
if (__builtin_expect (hook != NULL, 0))
|
||||
return (*hook)(bytes, RETURN_ADDRESS (0));
|
||||
|
||||
arena_lookup (ar_ptr);
|
||||
arena_get (ar_ptr, bytes);
|
||||
|
||||
arena_lock (ar_ptr, bytes);
|
||||
if (!ar_ptr)
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
/* Interposed malloc, version without threading support.
|
||||
Copyright (C) 2016 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#define INTERPOSE_THREADS 0
|
||||
#include "tst-interpose-aux.c"
|
||||
@@ -0,0 +1,20 @@
|
||||
/* Interposed malloc, version with threading support.
|
||||
Copyright (C) 2016 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#define INTERPOSE_THREADS 1
|
||||
#include "tst-interpose-aux.c"
|
||||
@@ -0,0 +1,270 @@
|
||||
/* Minimal malloc implementation for interposition tests.
|
||||
Copyright (C) 2016 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "tst-interpose-aux.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/uio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if INTERPOSE_THREADS
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
/* Print the error message and terminate the process with status 1. */
|
||||
__attribute__ ((noreturn))
|
||||
__attribute__ ((format (printf, 1, 2)))
|
||||
static void *
|
||||
fail (const char *format, ...)
|
||||
{
|
||||
/* This assumes that vsnprintf will not call malloc. It does not do
|
||||
so for the format strings we use. */
|
||||
char message[4096];
|
||||
va_list ap;
|
||||
va_start (ap, format);
|
||||
vsnprintf (message, sizeof (message), format, ap);
|
||||
va_end (ap);
|
||||
|
||||
enum { count = 3 };
|
||||
struct iovec iov[count];
|
||||
|
||||
iov[0].iov_base = (char *) "error: ";
|
||||
iov[1].iov_base = (char *) message;
|
||||
iov[2].iov_base = (char *) "\n";
|
||||
|
||||
for (int i = 0; i < count; ++i)
|
||||
iov[i].iov_len = strlen (iov[i].iov_base);
|
||||
|
||||
int unused __attribute__ ((unused));
|
||||
unused = writev (STDOUT_FILENO, iov, count);
|
||||
_exit (1);
|
||||
}
|
||||
|
||||
#if INTERPOSE_THREADS
|
||||
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
#endif
|
||||
|
||||
static void
|
||||
lock (void)
|
||||
{
|
||||
#if INTERPOSE_THREADS
|
||||
int ret = pthread_mutex_lock (&mutex);
|
||||
if (ret != 0)
|
||||
{
|
||||
errno = ret;
|
||||
fail ("pthread_mutex_lock: %m");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
unlock (void)
|
||||
{
|
||||
#if INTERPOSE_THREADS
|
||||
int ret = pthread_mutex_unlock (&mutex);
|
||||
if (ret != 0)
|
||||
{
|
||||
errno = ret;
|
||||
fail ("pthread_mutex_unlock: %m");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
struct __attribute__ ((aligned (__alignof__ (long double)))) allocation_header
|
||||
{
|
||||
size_t allocation_index;
|
||||
size_t allocation_size;
|
||||
};
|
||||
|
||||
/* Array of known allocations, to track invalid frees. */
|
||||
enum { max_allocations = 65536 };
|
||||
static struct allocation_header *allocations[max_allocations];
|
||||
static size_t allocation_index;
|
||||
static size_t deallocation_count;
|
||||
|
||||
/* Sanity check for successful malloc interposition. */
|
||||
__attribute__ ((destructor))
|
||||
static void
|
||||
check_for_allocations (void)
|
||||
{
|
||||
if (allocation_index == 0)
|
||||
{
|
||||
/* Make sure that malloc is called at least once from libc. */
|
||||
void *volatile ptr = strdup ("ptr");
|
||||
free (ptr);
|
||||
/* Compiler barrier. The strdup function calls malloc, which
|
||||
updates allocation_index, but strdup is marked __THROW, so
|
||||
the compiler could optimize away the reload. */
|
||||
__asm__ volatile ("" ::: "memory");
|
||||
/* If the allocation count is still zero, it means we did not
|
||||
interpose malloc successfully. */
|
||||
if (allocation_index == 0)
|
||||
fail ("malloc does not seem to have been interposed");
|
||||
}
|
||||
}
|
||||
|
||||
static struct allocation_header *get_header (const char *op, void *ptr)
|
||||
{
|
||||
struct allocation_header *header = ((struct allocation_header *) ptr) - 1;
|
||||
if (header->allocation_index >= allocation_index)
|
||||
fail ("%s: %p: invalid allocation index: %zu (not less than %zu)",
|
||||
op, ptr, header->allocation_index, allocation_index);
|
||||
if (allocations[header->allocation_index] != header)
|
||||
fail ("%s: %p: allocation pointer does not point to header, but %p",
|
||||
op, ptr, allocations[header->allocation_index]);
|
||||
return header;
|
||||
}
|
||||
|
||||
/* Internal helper functions. Those must be called while the lock is
|
||||
acquired. */
|
||||
|
||||
static void *
|
||||
malloc_internal (size_t size)
|
||||
{
|
||||
if (allocation_index == max_allocations)
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
size_t allocation_size = size + sizeof (struct allocation_header);
|
||||
if (allocation_size < size)
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t index = allocation_index++;
|
||||
void *result = mmap (NULL, allocation_size, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if (result == MAP_FAILED)
|
||||
return NULL;
|
||||
allocations[index] = result;
|
||||
*allocations[index] = (struct allocation_header)
|
||||
{
|
||||
.allocation_index = index,
|
||||
.allocation_size = allocation_size
|
||||
};
|
||||
return allocations[index] + 1;
|
||||
}
|
||||
|
||||
static void
|
||||
free_internal (const char *op, struct allocation_header *header)
|
||||
{
|
||||
size_t index = header->allocation_index;
|
||||
int result = mprotect (header, header->allocation_size, PROT_NONE);
|
||||
if (result != 0)
|
||||
fail ("%s: mprotect (%p, %zu): %m", op, header, header->allocation_size);
|
||||
/* Catch double-free issues. */
|
||||
allocations[index] = NULL;
|
||||
++deallocation_count;
|
||||
}
|
||||
|
||||
static void *
|
||||
realloc_internal (void *ptr, size_t new_size)
|
||||
{
|
||||
struct allocation_header *header = get_header ("realloc", ptr);
|
||||
size_t old_size = header->allocation_size - sizeof (struct allocation_header);
|
||||
if (old_size >= new_size)
|
||||
return ptr;
|
||||
|
||||
void *newptr = malloc_internal (new_size);
|
||||
if (newptr == NULL)
|
||||
return NULL;
|
||||
memcpy (newptr, ptr, old_size);
|
||||
free_internal ("realloc", header);
|
||||
return newptr;
|
||||
}
|
||||
|
||||
/* Public interfaces. These functions must perform locking. */
|
||||
|
||||
size_t
|
||||
malloc_allocation_count (void)
|
||||
{
|
||||
lock ();
|
||||
size_t count = allocation_index;
|
||||
unlock ();
|
||||
return count;
|
||||
}
|
||||
|
||||
size_t
|
||||
malloc_deallocation_count (void)
|
||||
{
|
||||
lock ();
|
||||
size_t count = deallocation_count;
|
||||
unlock ();
|
||||
return count;
|
||||
}
|
||||
void *
|
||||
malloc (size_t size)
|
||||
{
|
||||
lock ();
|
||||
void *result = malloc_internal (size);
|
||||
unlock ();
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
free (void *ptr)
|
||||
{
|
||||
if (ptr == NULL)
|
||||
return;
|
||||
lock ();
|
||||
struct allocation_header *header = get_header ("free", ptr);
|
||||
free_internal ("free", header);
|
||||
unlock ();
|
||||
}
|
||||
|
||||
void *
|
||||
calloc (size_t a, size_t b)
|
||||
{
|
||||
if (b > 0 && a > SIZE_MAX / b)
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
lock ();
|
||||
/* malloc_internal uses mmap, so the memory is zeroed. */
|
||||
void *result = malloc_internal (a * b);
|
||||
unlock ();
|
||||
return result;
|
||||
}
|
||||
|
||||
void *
|
||||
realloc (void *ptr, size_t n)
|
||||
{
|
||||
if (n ==0)
|
||||
{
|
||||
free (ptr);
|
||||
return NULL;
|
||||
}
|
||||
else if (ptr == NULL)
|
||||
return malloc (n);
|
||||
else
|
||||
{
|
||||
lock ();
|
||||
void *result = realloc_internal (ptr, n);
|
||||
unlock ();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/* Statistics interface for the minimal malloc implementation.
|
||||
Copyright (C) 2016 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef TST_INTERPOSE_AUX_H
|
||||
#define TST_INTERPOSE_AUX_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/* Return the number of allocations performed. */
|
||||
size_t malloc_allocation_count (void);
|
||||
|
||||
/* Return the number of deallocations performed. */
|
||||
size_t malloc_deallocation_count (void);
|
||||
|
||||
#endif /* TST_INTERPOSE_AUX_H */
|
||||
@@ -0,0 +1,20 @@
|
||||
/* Malloc interposition test, dynamically-linked version without threads.
|
||||
Copyright (C) 2016 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#define INTERPOSE_THREADS 0
|
||||
#include "tst-interpose-skeleton.c"
|
||||
@@ -0,0 +1,210 @@
|
||||
/* Test driver for malloc interposition tests.
|
||||
Copyright (C) 2016 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if INTERPOSE_THREADS
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
static int do_test (void);
|
||||
#define TEST_FUNCTION do_test ()
|
||||
#include "../test-skeleton.c"
|
||||
|
||||
/* Fills BUFFER with a test string. */
|
||||
static void
|
||||
line_string (int number, char *buffer, size_t length)
|
||||
{
|
||||
for (size_t i = 0; i < length - 2; ++i)
|
||||
buffer[i] = 'A' + ((number + i) % 26);
|
||||
buffer[length - 2] = '\n';
|
||||
buffer[length - 1] = '\0';
|
||||
}
|
||||
|
||||
/* Perform the tests. */
|
||||
static void *
|
||||
run_tests (void *closure)
|
||||
{
|
||||
char *temp_file_path;
|
||||
int fd = create_temp_file ("tst-malloc-interpose", &temp_file_path);
|
||||
if (fd < 0)
|
||||
_exit (1);
|
||||
|
||||
/* Line lengths excluding the line terminator. */
|
||||
static const int line_lengths[] = { 0, 45, 80, 2, 8201, 0, 17, -1 };
|
||||
|
||||
/* Fill the test file with data. */
|
||||
{
|
||||
FILE *fp = fdopen (fd, "w");
|
||||
for (int lineno = 0; line_lengths[lineno] >= 0; ++lineno)
|
||||
{
|
||||
char buffer[line_lengths[lineno] + 2];
|
||||
line_string (lineno, buffer, sizeof (buffer));
|
||||
fprintf (fp, "%s", buffer);
|
||||
}
|
||||
|
||||
if (ferror (fp))
|
||||
{
|
||||
printf ("error: fprintf: %m\n");
|
||||
_exit (1);
|
||||
}
|
||||
if (fclose (fp) != 0)
|
||||
{
|
||||
printf ("error: fclose: %m\n");
|
||||
_exit (1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Read the test file. This tests libc-internal allocation with
|
||||
realloc. */
|
||||
{
|
||||
FILE *fp = fopen (temp_file_path, "r");
|
||||
|
||||
char *actual = NULL;
|
||||
size_t actual_size = 0;
|
||||
for (int lineno = 0; ; ++lineno)
|
||||
{
|
||||
errno = 0;
|
||||
ssize_t result = getline (&actual, &actual_size, fp);
|
||||
if (result == 0)
|
||||
{
|
||||
printf ("error: invalid return value 0 from getline\n");
|
||||
_exit (1);
|
||||
}
|
||||
if (result < 0 && errno != 0)
|
||||
{
|
||||
printf ("error: getline: %m\n");
|
||||
_exit (1);
|
||||
}
|
||||
if (result < 0 && line_lengths[lineno] >= 0)
|
||||
{
|
||||
printf ("error: unexpected end of file after line %d\n", lineno);
|
||||
_exit (1);
|
||||
}
|
||||
if (result > 0 && line_lengths[lineno] < 0)
|
||||
{
|
||||
printf ("error: no end of file after line %d\n", lineno);
|
||||
_exit (1);
|
||||
}
|
||||
if (result == -1 && line_lengths[lineno] == -1)
|
||||
/* End of file reached as expected. */
|
||||
break;
|
||||
|
||||
if (result != line_lengths[lineno] + 1)
|
||||
{
|
||||
printf ("error: line length mismatch: expected %d, got %zd\n",
|
||||
line_lengths[lineno], result);
|
||||
_exit (1);
|
||||
}
|
||||
|
||||
char expected[line_lengths[lineno] + 2];
|
||||
line_string (lineno, expected, sizeof (expected));
|
||||
if (strcmp (actual, expected) != 0)
|
||||
{
|
||||
printf ("error: line mismatch\n");
|
||||
printf ("error: expected: [[%s]]\n", expected);
|
||||
printf ("error: actual: [[%s]]\n", actual);
|
||||
_exit (1);
|
||||
}
|
||||
}
|
||||
|
||||
if (fclose (fp) != 0)
|
||||
{
|
||||
printf ("error: fclose (after reading): %m\n");
|
||||
_exit (1);
|
||||
}
|
||||
}
|
||||
|
||||
free (temp_file_path);
|
||||
|
||||
/* Make sure that fork is working. */
|
||||
pid_t pid = fork ();
|
||||
if (pid == -1)
|
||||
{
|
||||
printf ("error: fork: %m\n");
|
||||
_exit (1);
|
||||
}
|
||||
enum { exit_code = 55 };
|
||||
if (pid == 0)
|
||||
_exit (exit_code);
|
||||
int status;
|
||||
int ret = waitpid (pid, &status, 0);
|
||||
if (ret < 0)
|
||||
{
|
||||
printf ("error: waitpid: %m\n");
|
||||
_exit (1);
|
||||
}
|
||||
if (!WIFEXITED (status) || WEXITSTATUS (status) != exit_code)
|
||||
{
|
||||
printf ("error: unexpected exit status from child process: %d\n",
|
||||
status);
|
||||
_exit (1);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* This is used to detect if malloc has not been successfully
|
||||
interposed. The interposed malloc does not use brk/sbrk. */
|
||||
static void *initial_brk;
|
||||
__attribute__ ((constructor))
|
||||
static void
|
||||
set_initial_brk (void)
|
||||
{
|
||||
initial_brk = sbrk (0);
|
||||
}
|
||||
|
||||
/* Terminate the process if the break value has been changed. */
|
||||
__attribute__ ((destructor))
|
||||
static void
|
||||
check_brk (void)
|
||||
{
|
||||
void *current = sbrk (0);
|
||||
if (current != initial_brk)
|
||||
{
|
||||
printf ("error: brk changed from %p to %p; no interposition?\n",
|
||||
initial_brk, current);
|
||||
_exit (1);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
check_brk ();
|
||||
|
||||
#if INTERPOSE_THREADS
|
||||
pthread_t thr;
|
||||
int ret;
|
||||
if ((ret = pthread_create (&thr, NULL, run_tests, NULL)) != 0)
|
||||
{
|
||||
errno = ret;
|
||||
printf ("error: %s failed: %m\n", __func__);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
#else
|
||||
run_tests (NULL);
|
||||
#endif
|
||||
|
||||
check_brk ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/* Malloc interposition test, static version without threads.
|
||||
Copyright (C) 2016 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "tst-interpose-nothread.c"
|
||||
@@ -0,0 +1,19 @@
|
||||
/* Malloc interposition test, static version with threads.
|
||||
Copyright (C) 2016 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "tst-interpose-nothread.c"
|
||||
@@ -0,0 +1,20 @@
|
||||
/* Malloc interposition test, dynamically-linked version with threads.
|
||||
Copyright (C) 2016 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#define INTERPOSE_THREADS 1
|
||||
#include "tst-interpose-skeleton.c"
|
||||
@@ -0,0 +1,220 @@
|
||||
/* Test concurrent fork, getline, and fflush (NULL).
|
||||
Copyright (C) 2016 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <malloc.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
static int do_test (void);
|
||||
#define TEST_FUNCTION do_test ()
|
||||
#include "../test-skeleton.c"
|
||||
|
||||
enum {
|
||||
/* Number of threads which call fork. */
|
||||
fork_thread_count = 4,
|
||||
/* Number of threads which call getline (and, indirectly,
|
||||
malloc). */
|
||||
read_thread_count = 8,
|
||||
};
|
||||
|
||||
static bool termination_requested;
|
||||
|
||||
static void *
|
||||
fork_thread_function (void *closure)
|
||||
{
|
||||
while (!__atomic_load_n (&termination_requested, __ATOMIC_RELAXED))
|
||||
{
|
||||
pid_t pid = fork ();
|
||||
if (pid < 0)
|
||||
{
|
||||
printf ("error: fork: %m\n");
|
||||
abort ();
|
||||
}
|
||||
else if (pid == 0)
|
||||
_exit (17);
|
||||
|
||||
int status;
|
||||
if (waitpid (pid, &status, 0) < 0)
|
||||
{
|
||||
printf ("error: waitpid: %m\n");
|
||||
abort ();
|
||||
}
|
||||
if (!WIFEXITED (status) || WEXITSTATUS (status) != 17)
|
||||
{
|
||||
printf ("error: waitpid returned invalid status: %d\n", status);
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char *file_to_read;
|
||||
|
||||
static void *
|
||||
read_thread_function (void *closure)
|
||||
{
|
||||
FILE *f = fopen (file_to_read, "r");
|
||||
if (f == NULL)
|
||||
{
|
||||
printf ("error: fopen (%s): %m\n", file_to_read);
|
||||
abort ();
|
||||
}
|
||||
|
||||
while (!__atomic_load_n (&termination_requested, __ATOMIC_RELAXED))
|
||||
{
|
||||
rewind (f);
|
||||
char *line = NULL;
|
||||
size_t line_allocated = 0;
|
||||
ssize_t ret = getline (&line, &line_allocated, f);
|
||||
if (ret < 0)
|
||||
{
|
||||
printf ("error: getline: %m\n");
|
||||
abort ();
|
||||
}
|
||||
free (line);
|
||||
}
|
||||
fclose (f);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *
|
||||
flushall_thread_function (void *closure)
|
||||
{
|
||||
while (!__atomic_load_n (&termination_requested, __ATOMIC_RELAXED))
|
||||
if (fflush (NULL) != 0)
|
||||
{
|
||||
printf ("error: fflush (NULL): %m\n");
|
||||
abort ();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
create_threads (pthread_t *threads, size_t count, void *(*func) (void *))
|
||||
{
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
{
|
||||
int ret = pthread_create (threads + i, NULL, func, NULL);
|
||||
if (ret != 0)
|
||||
{
|
||||
errno = ret;
|
||||
printf ("error: pthread_create: %m\n");
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
join_threads (pthread_t *threads, size_t count)
|
||||
{
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
{
|
||||
int ret = pthread_join (threads[i], NULL);
|
||||
if (ret != 0)
|
||||
{
|
||||
errno = ret;
|
||||
printf ("error: pthread_join: %m\n");
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Create a file which consists of a single long line, and assigns
|
||||
file_to_read. The hope is that this triggers an allocation in
|
||||
getline which needs a lock. */
|
||||
static void
|
||||
create_file_with_large_line (void)
|
||||
{
|
||||
int fd = create_temp_file ("bug19431-large-line", &file_to_read);
|
||||
if (fd < 0)
|
||||
{
|
||||
printf ("error: create_temp_file: %m\n");
|
||||
abort ();
|
||||
}
|
||||
FILE *f = fdopen (fd, "w+");
|
||||
if (f == NULL)
|
||||
{
|
||||
printf ("error: fdopen: %m\n");
|
||||
abort ();
|
||||
}
|
||||
for (int i = 0; i < 50000; ++i)
|
||||
fputc ('x', f);
|
||||
fputc ('\n', f);
|
||||
if (ferror (f))
|
||||
{
|
||||
printf ("error: fputc: %m\n");
|
||||
abort ();
|
||||
}
|
||||
if (fclose (f) != 0)
|
||||
{
|
||||
printf ("error: fclose: %m\n");
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
/* Make sure that we do not exceed the arena limit with the number
|
||||
of threads we configured. */
|
||||
if (mallopt (M_ARENA_MAX, 400) == 0)
|
||||
{
|
||||
printf ("error: mallopt (M_ARENA_MAX) failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Leave some room for shutting down all threads gracefully. */
|
||||
int timeout = 3;
|
||||
if (timeout > TIMEOUT)
|
||||
timeout = TIMEOUT - 1;
|
||||
|
||||
create_file_with_large_line ();
|
||||
|
||||
pthread_t fork_threads[fork_thread_count];
|
||||
create_threads (fork_threads, fork_thread_count, fork_thread_function);
|
||||
pthread_t read_threads[read_thread_count];
|
||||
create_threads (read_threads, read_thread_count, read_thread_function);
|
||||
pthread_t flushall_threads[1];
|
||||
create_threads (flushall_threads, 1, flushall_thread_function);
|
||||
|
||||
struct timespec ts = {timeout, 0};
|
||||
if (nanosleep (&ts, NULL))
|
||||
{
|
||||
printf ("error: error: nanosleep: %m\n");
|
||||
abort ();
|
||||
}
|
||||
|
||||
__atomic_store_n (&termination_requested, true, __ATOMIC_RELAXED);
|
||||
|
||||
join_threads (flushall_threads, 1);
|
||||
join_threads (read_threads, read_thread_count);
|
||||
join_threads (fork_threads, fork_thread_count);
|
||||
|
||||
free (file_to_read);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -332,8 +332,6 @@ this function is in @file{stdlib.h}.
|
||||
@c __libc_malloc @asulock @aculock @acsfd @acsmem
|
||||
@c force_reg ok
|
||||
@c *malloc_hook unguarded
|
||||
@c arena_lookup ok
|
||||
@c tsd_getspecific ok, TLS
|
||||
@c arena_lock @asulock @aculock @acsfd @acsmem
|
||||
@c mutex_lock @asulock @aculock
|
||||
@c arena_get2 @asulock @aculock @acsfd @acsmem
|
||||
@@ -341,7 +339,6 @@ this function is in @file{stdlib.h}.
|
||||
@c mutex_lock (list_lock) dup @asulock @aculock
|
||||
@c mutex_unlock (list_lock) dup @aculock
|
||||
@c mutex_lock (arena lock) dup @asulock @aculock [returns locked]
|
||||
@c tsd_setspecific ok, TLS
|
||||
@c __get_nprocs ext ok @acsfd
|
||||
@c NARENAS_FROM_NCORES ok
|
||||
@c catomic_compare_and_exchange_bool_acq ok
|
||||
@@ -835,7 +832,6 @@ is declared in @file{stdlib.h}.
|
||||
@c *__malloc_hook dup unguarded
|
||||
@c memset dup ok
|
||||
@c arena_get @asulock @aculock @acsfd @acsmem
|
||||
@c arena_lookup dup ok
|
||||
@c arena_lock dup @asulock @aculock @acsfd @acsmem
|
||||
@c top dup ok
|
||||
@c chunksize dup ok
|
||||
@@ -1055,14 +1051,6 @@ systems that do not support @w{ISO C11}.
|
||||
@c _dl_addr_inside_object ok
|
||||
@c determine_info ok
|
||||
@c __rtld_lock_unlock_recursive (dl_load_lock) @aculock
|
||||
@c thread_atfork @asulock @aculock @acsfd @acsmem
|
||||
@c __register_atfork @asulock @aculock @acsfd @acsmem
|
||||
@c lll_lock (__fork_lock) @asulock @aculock
|
||||
@c fork_handler_alloc @asulock @aculock @acsfd @acsmem
|
||||
@c calloc dup @asulock @aculock @acsfd @acsmem
|
||||
@c __linkin_atfork ok
|
||||
@c catomic_compare_and_exchange_bool_acq ok
|
||||
@c lll_unlock (__fork_lock) @aculock
|
||||
@c *_environ @mtsenv
|
||||
@c next_env_entry ok
|
||||
@c strcspn dup ok
|
||||
|
||||
+2
-1
@@ -76,7 +76,8 @@ install-lib := libg.a
|
||||
gpl2lgpl := error.c error.h
|
||||
|
||||
tests := tst-dirname tst-tsearch tst-fdset tst-efgcvt tst-mntent tst-hsearch \
|
||||
tst-error1 tst-pselect tst-insremque tst-mntent2 bug-hsearch1
|
||||
tst-error1 tst-pselect tst-insremque tst-mntent2 bug-hsearch1 \
|
||||
tst-mntent-blank-corrupt tst-mntent-blank-passno bug18240
|
||||
ifeq ($(run-built-tests),yes)
|
||||
tests-special += $(objpfx)tst-error1-mem.out
|
||||
endif
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/* Test integer wraparound in hcreate.
|
||||
Copyright (C) 2016 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <search.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
static void
|
||||
test_size (size_t size)
|
||||
{
|
||||
int res = hcreate (size);
|
||||
if (res == 0)
|
||||
{
|
||||
if (errno == ENOMEM)
|
||||
return;
|
||||
printf ("error: hcreate (%zu): %m\n", size);
|
||||
exit (1);
|
||||
}
|
||||
char *keys[100];
|
||||
for (int i = 0; i < 100; ++i)
|
||||
{
|
||||
if (asprintf (keys + i, "%d", i) < 0)
|
||||
{
|
||||
printf ("error: asprintf: %m\n");
|
||||
exit (1);
|
||||
}
|
||||
ENTRY e = { keys[i], (char *) "value" };
|
||||
if (hsearch (e, ENTER) == NULL)
|
||||
{
|
||||
printf ("error: hsearch (\"%s\"): %m\n", keys[i]);
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
hdestroy ();
|
||||
|
||||
for (int i = 0; i < 100; ++i)
|
||||
free (keys[i]);
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
/* Limit the size of the process, so that memory allocation will
|
||||
fail without impacting the entire system. */
|
||||
{
|
||||
struct rlimit limit;
|
||||
if (getrlimit (RLIMIT_AS, &limit) != 0)
|
||||
{
|
||||
printf ("getrlimit (RLIMIT_AS) failed: %m\n");
|
||||
return 1;
|
||||
}
|
||||
long target = 100 * 1024 * 1024;
|
||||
if (limit.rlim_cur == RLIM_INFINITY || limit.rlim_cur > target)
|
||||
{
|
||||
limit.rlim_cur = target;
|
||||
if (setrlimit (RLIMIT_AS, &limit) != 0)
|
||||
{
|
||||
printf ("setrlimit (RLIMIT_AS) failed: %m\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test_size (500);
|
||||
test_size (-1);
|
||||
test_size (-3);
|
||||
test_size (INT_MAX - 2);
|
||||
test_size (INT_MAX - 1);
|
||||
test_size (INT_MAX);
|
||||
test_size (((unsigned) INT_MAX) + 1);
|
||||
test_size (UINT_MAX - 2);
|
||||
test_size (UINT_MAX - 1);
|
||||
test_size (UINT_MAX);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define TEST_FUNCTION do_test ()
|
||||
#include "../test-skeleton.c"
|
||||
+18
-12
@@ -19,7 +19,7 @@
|
||||
#include <errno.h>
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <search.h>
|
||||
|
||||
/* [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986
|
||||
@@ -46,15 +46,12 @@ static int
|
||||
isprime (unsigned int number)
|
||||
{
|
||||
/* no even number will be passed */
|
||||
unsigned int div = 3;
|
||||
|
||||
while (div * div < number && number % div != 0)
|
||||
div += 2;
|
||||
|
||||
return number % div != 0;
|
||||
for (unsigned int div = 3; div <= number / div; div += 2)
|
||||
if (number % div == 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Before using the hash table we must allocate memory for it.
|
||||
Test for an existing table are done. We allocate one element
|
||||
more as the found prime number says. This is done for more effective
|
||||
@@ -81,10 +78,19 @@ hcreate_r (nel, htab)
|
||||
use will not work. */
|
||||
if (nel < 3)
|
||||
nel = 3;
|
||||
/* Change nel to the first prime number not smaller as nel. */
|
||||
nel |= 1; /* make odd */
|
||||
while (!isprime (nel))
|
||||
nel += 2;
|
||||
|
||||
/* Change nel to the first prime number in the range [nel, UINT_MAX - 2],
|
||||
The '- 2' means 'nel += 2' cannot overflow. */
|
||||
for (nel |= 1; ; nel += 2)
|
||||
{
|
||||
if (UINT_MAX - 2 < nel)
|
||||
{
|
||||
__set_errno (ENOMEM);
|
||||
return 0;
|
||||
}
|
||||
if (isprime (nel))
|
||||
break;
|
||||
}
|
||||
|
||||
htab->size = nel;
|
||||
htab->filled = 0;
|
||||
|
||||
+3
-1
@@ -136,7 +136,9 @@ __getmntent_r (FILE *stream, struct mntent *mp, char *buffer, int bufsiz)
|
||||
end_ptr = strchr (buffer, '\n');
|
||||
if (end_ptr != NULL) /* chop newline */
|
||||
{
|
||||
while (end_ptr[-1] == ' ' || end_ptr[-1] == '\t')
|
||||
/* Do not walk past the start of buffer if it's all whitespace. */
|
||||
while (end_ptr != buffer
|
||||
&& (end_ptr[-1] == ' ' || end_ptr[-1] == '\t'))
|
||||
end_ptr--;
|
||||
*end_ptr = '\0';
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/* Make sure blank lines does not cause memory corruption BZ #18887.
|
||||
|
||||
Copyright (C) 2009-2015 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for 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 <mntent.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Make sure blank lines don't trigger memory corruption. This doesn't happen
|
||||
for all targets though, so it's a best effort test BZ #18887. */
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
fp = tmpfile ();
|
||||
fputs ("\n \n/foo\\040dir /bar\\040dir auto bind \t \n", fp);
|
||||
rewind (fp);
|
||||
|
||||
/* The corruption happens here ... */
|
||||
getmntent (fp);
|
||||
/* ... but trigers here. */
|
||||
endmntent (fp);
|
||||
|
||||
/* If the test failed, we would crash, and not hit this point. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define TEST_FUNCTION do_test ()
|
||||
#include "../test-skeleton.c"
|
||||
@@ -0,0 +1,53 @@
|
||||
/* Make sure trailing whitespace is handled properly BZ #17273.
|
||||
|
||||
Copyright (C) 2009-2015 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for 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 <mntent.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Check entries to make sure trailing whitespace is ignored and we return the
|
||||
correct passno value BZ #17273. */
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
int result = 0;
|
||||
FILE *fp;
|
||||
struct mntent *mnt;
|
||||
|
||||
fp = tmpfile ();
|
||||
fputs ("/foo\\040dir /bar\\040dir auto bind \t \n", fp);
|
||||
rewind (fp);
|
||||
|
||||
mnt = getmntent (fp);
|
||||
if (strcmp (mnt->mnt_fsname, "/foo dir") != 0
|
||||
|| strcmp (mnt->mnt_dir, "/bar dir") != 0
|
||||
|| strcmp (mnt->mnt_type, "auto") != 0
|
||||
|| strcmp (mnt->mnt_opts, "bind") != 0
|
||||
|| mnt->mnt_freq != 0
|
||||
|| mnt->mnt_passno != 0)
|
||||
{
|
||||
puts ("Error while reading entry with trailing whitespaces");
|
||||
result = 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#define TEST_FUNCTION do_test ()
|
||||
#include "../test-skeleton.c"
|
||||
@@ -73,26 +73,6 @@ main (int argc, char *argv[])
|
||||
puts ("Error while reading written entry back in");
|
||||
result = 1;
|
||||
}
|
||||
|
||||
/* Part III: Entry with whitespaces at the end of a line. */
|
||||
rewind (fp);
|
||||
|
||||
fputs ("/foo\\040dir /bar\\040dir auto bind \t \n", fp);
|
||||
|
||||
rewind (fp);
|
||||
|
||||
mnt = getmntent (fp);
|
||||
|
||||
if (strcmp (mnt->mnt_fsname, "/foo dir") != 0
|
||||
|| strcmp (mnt->mnt_dir, "/bar dir") != 0
|
||||
|| strcmp (mnt->mnt_type, "auto") != 0
|
||||
|| strcmp (mnt->mnt_opts, "bind") != 0
|
||||
|| mnt->mnt_freq != 0
|
||||
|| mnt->mnt_passno != 0)
|
||||
{
|
||||
puts ("Error while reading entry with trailing whitespaces");
|
||||
result = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
+11
-9
@@ -680,16 +680,18 @@ nis_server_cache_add (const_nis_name name, int search_parent,
|
||||
/* Choose which entry should be evicted from the cache. */
|
||||
loc = &nis_server_cache[0];
|
||||
if (*loc != NULL)
|
||||
for (i = 1; i < 16; ++i)
|
||||
if (nis_server_cache[i] == NULL)
|
||||
{
|
||||
{
|
||||
for (i = 1; i < 16; ++i)
|
||||
if (nis_server_cache[i] == NULL)
|
||||
{
|
||||
loc = &nis_server_cache[i];
|
||||
break;
|
||||
}
|
||||
else if ((*loc)->uses > nis_server_cache[i]->uses
|
||||
|| ((*loc)->uses == nis_server_cache[i]->uses
|
||||
&& (*loc)->expires > nis_server_cache[i]->expires))
|
||||
loc = &nis_server_cache[i];
|
||||
break;
|
||||
}
|
||||
else if ((*loc)->uses > nis_server_cache[i]->uses
|
||||
|| ((*loc)->uses == nis_server_cache[i]->uses
|
||||
&& (*loc)->expires > nis_server_cache[i]->expires))
|
||||
loc = &nis_server_cache[i];
|
||||
}
|
||||
old = *loc;
|
||||
*loc = new;
|
||||
|
||||
|
||||
+6
-2
@@ -301,8 +301,8 @@ tests += tst-cancelx2 tst-cancelx3 tst-cancelx4 tst-cancelx5 \
|
||||
tst-oncex3 tst-oncex4
|
||||
endif
|
||||
ifeq ($(build-shared),yes)
|
||||
tests += tst-atfork2 tst-tls3 tst-tls4 tst-tls5 tst-_res1 tst-fini1 \
|
||||
tst-stackguard1
|
||||
tests += tst-atfork2 tst-tls3 tst-tls3-malloc tst-tls4 tst-tls5 tst-_res1 \
|
||||
tst-fini1 tst-stackguard1
|
||||
tests-nolibpthread += tst-fini1
|
||||
ifeq ($(have-z-execstack),yes)
|
||||
tests += tst-execstack
|
||||
@@ -500,6 +500,10 @@ LDFLAGS-tst-tls3 = -rdynamic
|
||||
$(objpfx)tst-tls3.out: $(objpfx)tst-tls3mod.so
|
||||
$(objpfx)tst-tls3mod.so: $(shared-thread-library)
|
||||
|
||||
$(objpfx)tst-tls3-malloc: $(libdl) $(shared-thread-library)
|
||||
LDFLAGS-tst-tls3-malloc = -rdynamic
|
||||
$(objpfx)tst-tls3-malloc.out: $(objpfx)tst-tls3mod.so
|
||||
|
||||
$(objpfx)tst-tls4: $(libdl) $(shared-thread-library)
|
||||
$(objpfx)tst-tls4.out: $(objpfx)tst-tls4moda.so $(objpfx)tst-tls4modb.so
|
||||
|
||||
|
||||
@@ -244,9 +244,7 @@ get_cached_stack (size_t *sizep, void **memp)
|
||||
/* Clear the DTV. */
|
||||
dtv_t *dtv = GET_DTV (TLS_TPADJ (result));
|
||||
for (size_t cnt = 0; cnt < dtv[-1].counter; ++cnt)
|
||||
if (! dtv[1 + cnt].pointer.is_static
|
||||
&& dtv[1 + cnt].pointer.val != TLS_DTV_UNALLOCATED)
|
||||
free (dtv[1 + cnt].pointer.val);
|
||||
free (dtv[1 + cnt].pointer.to_free);
|
||||
memset (dtv, '\0', (dtv[-1].counter + 1) * sizeof (dtv_t));
|
||||
|
||||
/* Re-initialize the TLS. */
|
||||
@@ -1190,7 +1188,6 @@ __nptl_setxid (struct xid_command *cmdp)
|
||||
static inline void __attribute__((always_inline))
|
||||
init_one_static_tls (struct pthread *curp, struct link_map *map)
|
||||
{
|
||||
dtv_t *dtv = GET_DTV (TLS_TPADJ (curp));
|
||||
# if TLS_TCB_AT_TP
|
||||
void *dest = (char *) curp - map->l_tls_offset;
|
||||
# elif TLS_DTV_AT_TP
|
||||
@@ -1199,11 +1196,9 @@ init_one_static_tls (struct pthread *curp, struct link_map *map)
|
||||
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
|
||||
# endif
|
||||
|
||||
/* Fill in the DTV slot so that a later LD/GD access will find it. */
|
||||
dtv[map->l_tls_modid].pointer.val = dest;
|
||||
dtv[map->l_tls_modid].pointer.is_static = true;
|
||||
|
||||
/* Initialize the memory. */
|
||||
/* We cannot delay the initialization of the Static TLS area, since
|
||||
it can be accessed with LE or IE, but since the DTV is only used
|
||||
by GD and LD, we can delay its update to avoid a race. */
|
||||
memset (__mempcpy (dest, map->l_tls_initimage, map->l_tls_initimage_size),
|
||||
'\0', map->l_tls_blocksize - map->l_tls_initimage_size);
|
||||
}
|
||||
|
||||
+20
-19
@@ -46,14 +46,8 @@ int *__libc_multiple_threads_ptr attribute_hidden;
|
||||
size_t __static_tls_size;
|
||||
size_t __static_tls_align_m1;
|
||||
|
||||
#ifndef __ASSUME_SET_ROBUST_LIST
|
||||
/* Negative if we do not have the system call and we can use it. */
|
||||
int __set_robust_list_avail;
|
||||
# define set_robust_list_not_avail() \
|
||||
__set_robust_list_avail = -1
|
||||
#else
|
||||
# define set_robust_list_not_avail() do { } while (0)
|
||||
#endif
|
||||
|
||||
#ifndef __ASSUME_FUTEX_CLOCK_REALTIME
|
||||
/* Nonzero if we do not have FUTEX_CLOCK_REALTIME. */
|
||||
@@ -324,19 +318,21 @@ __pthread_initialize_minimal_internal (void)
|
||||
#endif
|
||||
|
||||
/* Initialize the robust mutex data. */
|
||||
{
|
||||
#ifdef __PTHREAD_MUTEX_HAVE_PREV
|
||||
pd->robust_prev = &pd->robust_head;
|
||||
pd->robust_prev = &pd->robust_head;
|
||||
#endif
|
||||
pd->robust_head.list = &pd->robust_head;
|
||||
#ifdef __NR_set_robust_list
|
||||
pd->robust_head.futex_offset = (offsetof (pthread_mutex_t, __data.__lock)
|
||||
- offsetof (pthread_mutex_t,
|
||||
__data.__list.__next));
|
||||
int res = INTERNAL_SYSCALL (set_robust_list, err, 2, &pd->robust_head,
|
||||
sizeof (struct robust_list_head));
|
||||
if (INTERNAL_SYSCALL_ERROR_P (res, err))
|
||||
#endif
|
||||
set_robust_list_not_avail ();
|
||||
pd->robust_head.list = &pd->robust_head;
|
||||
|
||||
pd->robust_head.futex_offset = (offsetof (pthread_mutex_t, __data.__lock)
|
||||
- offsetof (pthread_mutex_t,
|
||||
__data.__list.__next));
|
||||
INTERNAL_SYSCALL_DECL (err);
|
||||
int res = INTERNAL_SYSCALL (set_robust_list, err, 2, &pd->robust_head,
|
||||
sizeof (struct robust_list_head));
|
||||
if (INTERNAL_SYSCALL_ERROR_P (res, err))
|
||||
__set_robust_list_avail = -1;
|
||||
}
|
||||
|
||||
#ifdef __NR_futex
|
||||
# ifndef __ASSUME_PRIVATE_FUTEX
|
||||
@@ -344,6 +340,7 @@ __pthread_initialize_minimal_internal (void)
|
||||
doing the test once this early is beneficial. */
|
||||
{
|
||||
int word = 0;
|
||||
INTERNAL_SYSCALL_DECL (err);
|
||||
word = INTERNAL_SYSCALL (futex, err, 3, &word,
|
||||
FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1);
|
||||
if (!INTERNAL_SYSCALL_ERROR_P (word, err))
|
||||
@@ -364,6 +361,7 @@ __pthread_initialize_minimal_internal (void)
|
||||
is irrelevant. Given that passing six parameters is difficult
|
||||
on some architectures we just pass whatever random value the
|
||||
calling convention calls for to the kernel. It causes no harm. */
|
||||
INTERNAL_SYSCALL_DECL (err);
|
||||
word = INTERNAL_SYSCALL (futex, err, 5, &word,
|
||||
FUTEX_WAIT_BITSET | FUTEX_CLOCK_REALTIME
|
||||
| FUTEX_PRIVATE_FLAG, 1, NULL, 0);
|
||||
@@ -416,8 +414,11 @@ __pthread_initialize_minimal_internal (void)
|
||||
# ifdef SIGSETXID
|
||||
__sigaddset (&sa.sa_mask, SIGSETXID);
|
||||
# endif
|
||||
(void) INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_UNBLOCK, &sa.sa_mask,
|
||||
NULL, _NSIG / 8);
|
||||
{
|
||||
INTERNAL_SYSCALL_DECL (err);
|
||||
(void) INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_UNBLOCK, &sa.sa_mask,
|
||||
NULL, _NSIG / 8);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Get the size of the static and alignment requirements for the TLS
|
||||
|
||||
+14
-11
@@ -199,10 +199,8 @@ hidden_proto (__pthread_keys)
|
||||
/* Number of threads running. */
|
||||
extern unsigned int __nptl_nthreads attribute_hidden;
|
||||
|
||||
#ifndef __ASSUME_SET_ROBUST_LIST
|
||||
/* Negative if we do not have the system call and we can use it. */
|
||||
extern int __set_robust_list_avail attribute_hidden;
|
||||
#endif
|
||||
|
||||
/* Thread Priority Protection. */
|
||||
extern int __sched_fifo_min_prio attribute_hidden;
|
||||
@@ -582,17 +580,22 @@ extern void __wait_lookup_done (void) attribute_hidden;
|
||||
# define PTHREAD_STATIC_FN_REQUIRE(name) __asm (".globl " #name);
|
||||
#endif
|
||||
|
||||
extern bool __prio_inherit_missing (void);
|
||||
|
||||
/* Test if the mutex is suitable for the FUTEX_WAIT_REQUEUE_PI operation. */
|
||||
#if (defined lll_futex_wait_requeue_pi \
|
||||
&& defined __ASSUME_REQUEUE_PI)
|
||||
# define USE_REQUEUE_PI(mut) \
|
||||
((mut) && (mut) != (void *) ~0l \
|
||||
&& (((mut)->__data.__kind \
|
||||
& (PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_ROBUST_NORMAL_NP)) \
|
||||
== PTHREAD_MUTEX_PRIO_INHERIT_NP))
|
||||
#else
|
||||
# define USE_REQUEUE_PI(mut) 0
|
||||
static inline bool
|
||||
use_requeue_pi (pthread_mutex_t *mut)
|
||||
{
|
||||
#ifndef __ASSUME_REQUEUE_PI
|
||||
if (__prio_inherit_missing ())
|
||||
return false;
|
||||
#endif
|
||||
return (mut) &&
|
||||
(mut) != (void *) ~0l &&
|
||||
(((mut)->__data.__kind
|
||||
& (PTHREAD_MUTEX_PRIO_INHERIT_NP | PTHREAD_MUTEX_ROBUST_NORMAL_NP)) ==
|
||||
PTHREAD_MUTEX_PRIO_INHERIT_NP);
|
||||
}
|
||||
|
||||
/* Returns 0 if POL is a valid scheduling policy. */
|
||||
static inline int
|
||||
|
||||
@@ -61,9 +61,8 @@ __pthread_cond_broadcast (cond)
|
||||
|| PTHREAD_MUTEX_PSHARED (mut) & PTHREAD_MUTEX_PSHARED_BIT)
|
||||
goto wake_all;
|
||||
|
||||
#if (defined lll_futex_cmp_requeue_pi \
|
||||
&& defined __ASSUME_REQUEUE_PI)
|
||||
if (USE_REQUEUE_PI (mut))
|
||||
#ifdef lll_futex_cmp_requeue_pi
|
||||
if (use_requeue_pi (mut))
|
||||
{
|
||||
if (lll_futex_cmp_requeue_pi (&cond->__data.__futex, 1, INT_MAX,
|
||||
&mut->__data.__lock, futex_val,
|
||||
|
||||
@@ -47,11 +47,10 @@ __pthread_cond_signal (cond)
|
||||
++cond->__data.__wakeup_seq;
|
||||
++cond->__data.__futex;
|
||||
|
||||
#if (defined lll_futex_cmp_requeue_pi \
|
||||
&& defined __ASSUME_REQUEUE_PI)
|
||||
#ifdef lll_futex_cmp_requeue_pi
|
||||
pthread_mutex_t *mut = cond->__data.__mutex;
|
||||
|
||||
if (USE_REQUEUE_PI (mut)
|
||||
if (use_requeue_pi (mut)
|
||||
/* This can only really fail with a ENOSYS, since nobody can modify
|
||||
futex while we have the cond_lock. */
|
||||
&& lll_futex_cmp_requeue_pi (&cond->__data.__futex, 1, 0,
|
||||
|
||||
@@ -63,8 +63,7 @@ __pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex,
|
||||
int pshared = (cond->__data.__mutex == (void *) ~0l)
|
||||
? LLL_SHARED : LLL_PRIVATE;
|
||||
|
||||
#if (defined lll_futex_timed_wait_requeue_pi \
|
||||
&& defined __ASSUME_REQUEUE_PI)
|
||||
#ifdef lll_futex_timed_wait_requeue_pi
|
||||
int pi_flag = 0;
|
||||
#endif
|
||||
|
||||
@@ -161,8 +160,7 @@ __pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex,
|
||||
|
||||
/* REQUEUE_PI was implemented after FUTEX_CLOCK_REALTIME, so it is sufficient
|
||||
to check just the former. */
|
||||
#if (defined lll_futex_timed_wait_requeue_pi \
|
||||
&& defined __ASSUME_REQUEUE_PI)
|
||||
#ifdef lll_futex_timed_wait_requeue_pi
|
||||
/* If pi_flag remained 1 then it means that we had the lock and the mutex
|
||||
but a spurious waker raced ahead of us. Give back the mutex before
|
||||
going into wait again. */
|
||||
@@ -171,7 +169,7 @@ __pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex,
|
||||
__pthread_mutex_cond_lock_adjust (mutex);
|
||||
__pthread_mutex_unlock_usercnt (mutex, 0);
|
||||
}
|
||||
pi_flag = USE_REQUEUE_PI (mutex);
|
||||
pi_flag = use_requeue_pi (mutex);
|
||||
|
||||
if (pi_flag)
|
||||
{
|
||||
@@ -250,8 +248,7 @@ __pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex,
|
||||
__pthread_cleanup_pop (&buffer, 0);
|
||||
|
||||
/* Get the mutex before returning. */
|
||||
#if (defined lll_futex_timed_wait_requeue_pi \
|
||||
&& defined __ASSUME_REQUEUE_PI)
|
||||
#ifdef lll_futex_timed_wait_requeue_pi
|
||||
if (pi_flag)
|
||||
{
|
||||
__pthread_mutex_cond_lock_adjust (mutex);
|
||||
|
||||
@@ -86,7 +86,7 @@ __condvar_cleanup (void *arg)
|
||||
|
||||
/* Get the mutex before returning unless asynchronous cancellation
|
||||
is in effect. We don't try to get the mutex if we already own it. */
|
||||
if (!(USE_REQUEUE_PI (cbuffer->mutex))
|
||||
if (!(use_requeue_pi (cbuffer->mutex))
|
||||
|| ((cbuffer->mutex->__data.__lock & FUTEX_TID_MASK)
|
||||
!= THREAD_GETMEM (THREAD_SELF, tid)))
|
||||
{
|
||||
@@ -106,8 +106,7 @@ __pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)
|
||||
int pshared = (cond->__data.__mutex == (void *) ~0l)
|
||||
? LLL_SHARED : LLL_PRIVATE;
|
||||
|
||||
#if (defined lll_futex_wait_requeue_pi \
|
||||
&& defined __ASSUME_REQUEUE_PI)
|
||||
#ifdef lll_futex_wait_requeue_pi
|
||||
int pi_flag = 0;
|
||||
#endif
|
||||
|
||||
@@ -160,8 +159,7 @@ __pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)
|
||||
/* Enable asynchronous cancellation. Required by the standard. */
|
||||
cbuffer.oldtype = __pthread_enable_asynccancel ();
|
||||
|
||||
#if (defined lll_futex_wait_requeue_pi \
|
||||
&& defined __ASSUME_REQUEUE_PI)
|
||||
#ifdef lll_futex_wait_requeue_pi
|
||||
/* If pi_flag remained 1 then it means that we had the lock and the mutex
|
||||
but a spurious waker raced ahead of us. Give back the mutex before
|
||||
going into wait again. */
|
||||
@@ -170,7 +168,7 @@ __pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)
|
||||
__pthread_mutex_cond_lock_adjust (mutex);
|
||||
__pthread_mutex_unlock_usercnt (mutex, 0);
|
||||
}
|
||||
pi_flag = USE_REQUEUE_PI (mutex);
|
||||
pi_flag = use_requeue_pi (mutex);
|
||||
|
||||
if (pi_flag)
|
||||
{
|
||||
@@ -221,8 +219,7 @@ __pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)
|
||||
__pthread_cleanup_pop (&buffer, 0);
|
||||
|
||||
/* Get the mutex before returning. Not needed for PI. */
|
||||
#if (defined lll_futex_wait_requeue_pi \
|
||||
&& defined __ASSUME_REQUEUE_PI)
|
||||
#ifdef lll_futex_wait_requeue_pi
|
||||
if (pi_flag)
|
||||
{
|
||||
__pthread_mutex_cond_lock_adjust (mutex);
|
||||
|
||||
@@ -271,10 +271,7 @@ START_THREAD_DEFN
|
||||
if (__glibc_unlikely (atomic_exchange_acq (&pd->setxid_futex, 0) == -2))
|
||||
lll_futex_wake (&pd->setxid_futex, 1, LLL_PRIVATE);
|
||||
|
||||
#ifdef __NR_set_robust_list
|
||||
# ifndef __ASSUME_SET_ROBUST_LIST
|
||||
if (__set_robust_list_avail >= 0)
|
||||
# endif
|
||||
if (__glibc_likely (__set_robust_list_avail >= 0))
|
||||
{
|
||||
INTERNAL_SYSCALL_DECL (err);
|
||||
/* This call should never fail because the initial call in init.c
|
||||
@@ -282,7 +279,6 @@ START_THREAD_DEFN
|
||||
INTERNAL_SYSCALL (set_robust_list, err, 2, &pd->robust_head,
|
||||
sizeof (struct robust_list_head));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SIGCANCEL
|
||||
/* If the parent was running cancellation handlers while creating
|
||||
@@ -388,7 +384,6 @@ START_THREAD_DEFN
|
||||
the breakpoint reports TD_THR_RUN state rather than TD_THR_ZOMBIE. */
|
||||
atomic_bit_set (&pd->cancelhandling, EXITING_BIT);
|
||||
|
||||
#ifndef __ASSUME_SET_ROBUST_LIST
|
||||
/* If this thread has any robust mutexes locked, handle them now. */
|
||||
# ifdef __PTHREAD_MUTEX_HAVE_PREV
|
||||
void *robust = pd->robust_head.list;
|
||||
@@ -418,7 +413,6 @@ START_THREAD_DEFN
|
||||
}
|
||||
while (robust != (void *) &pd->robust_head);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Mark the memory of the stack as usable to the kernel. We free
|
||||
everything except for the space used for the TCB itself. */
|
||||
|
||||
@@ -33,11 +33,11 @@ static const struct pthread_mutexattr default_mutexattr =
|
||||
};
|
||||
|
||||
|
||||
static bool
|
||||
prio_inherit_missing (void)
|
||||
bool
|
||||
attribute_hidden
|
||||
__prio_inherit_missing (void)
|
||||
{
|
||||
#ifdef __NR_futex
|
||||
# ifndef __ASSUME_FUTEX_LOCK_PI
|
||||
static int tpi_supported;
|
||||
if (__glibc_unlikely (tpi_supported == 0))
|
||||
{
|
||||
@@ -48,8 +48,6 @@ prio_inherit_missing (void)
|
||||
tpi_supported = INTERNAL_SYSCALL_ERRNO (ret, err) == ENOSYS ? -1 : 1;
|
||||
}
|
||||
return __glibc_unlikely (tpi_supported < 0);
|
||||
# endif
|
||||
return false;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
@@ -76,7 +74,7 @@ __pthread_mutex_init (mutex, mutexattr)
|
||||
break;
|
||||
|
||||
case PTHREAD_PRIO_INHERIT << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT:
|
||||
if (__glibc_unlikely (prio_inherit_missing ()))
|
||||
if (__glibc_unlikely (__prio_inherit_missing ()))
|
||||
return ENOTSUP;
|
||||
break;
|
||||
|
||||
@@ -95,11 +93,9 @@ __pthread_mutex_init (mutex, mutexattr)
|
||||
|
||||
if ((imutexattr->mutexkind & PTHREAD_MUTEXATTR_FLAG_ROBUST) != 0)
|
||||
{
|
||||
#ifndef __ASSUME_SET_ROBUST_LIST
|
||||
if ((imutexattr->mutexkind & PTHREAD_MUTEXATTR_FLAG_PSHARED) != 0
|
||||
&& __set_robust_list_avail < 0)
|
||||
return ENOTSUP;
|
||||
#endif
|
||||
|
||||
mutex->__data.__kind |= PTHREAD_MUTEX_ROBUST_NORMAL_NP;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/* Test TLS allocation with an interposed malloc.
|
||||
Copyright (C) 2016 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Reuse the test. */
|
||||
#define STACK_SIZE_MB 5
|
||||
#include "tst-tls3.c"
|
||||
|
||||
/* Increase the thread stack size to 10 MiB, so that some thread
|
||||
stacks are actually freed. (The stack cache size is currently
|
||||
hard-wired to 40 MiB in allocatestack.c.) */
|
||||
static long stack_size_in_mb = 10;
|
||||
|
||||
#include <sys/mman.h>
|
||||
|
||||
#define INTERPOSE_THREADS 1
|
||||
#include "../malloc/tst-interpose-aux.c"
|
||||
+9
-1
@@ -29,6 +29,11 @@
|
||||
|
||||
#define THE_SIG SIGUSR1
|
||||
|
||||
/* The stack size can be overriden. With a sufficiently large stack
|
||||
size, thread stacks for terminated threads are freed, but this does
|
||||
not happen with the default size of 1 MiB. */
|
||||
enum { default_stack_size_in_mb = 1 };
|
||||
static long stack_size_in_mb;
|
||||
|
||||
#define N 10
|
||||
static pthread_t th[N];
|
||||
@@ -72,6 +77,9 @@ int nsigs;
|
||||
int
|
||||
do_test (void)
|
||||
{
|
||||
if (stack_size_in_mb == 0)
|
||||
stack_size_in_mb = default_stack_size_in_mb;
|
||||
|
||||
if ((uintptr_t) pthread_self () & (TCB_ALIGNMENT - 1))
|
||||
{
|
||||
puts ("initial thread's struct pthread not aligned enough");
|
||||
@@ -127,7 +135,7 @@ do_test (void)
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (pthread_attr_setstacksize (&a, 1 * 1024 * 1024) != 0)
|
||||
if (pthread_attr_setstacksize (&a, stack_size_in_mb * 1024 * 1024) != 0)
|
||||
{
|
||||
puts ("attr_setstacksize failed");
|
||||
return 1;
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
# we've just built. It checks for all the symbols used in td_symbol_list.
|
||||
|
||||
BEGIN {
|
||||
%define DB_RTLD_VARIABLE(name) /* Nothing. */
|
||||
%define DB_MAIN_VARIABLE(name) /* Nothing. */
|
||||
%define DB_LOOKUP_NAME(idx, name) required[STRINGIFY (name)] = 1;
|
||||
%define DB_LOOKUP_NAME_TH_UNIQUE(idx, name) th_unique[STRINGIFY (name)] = 1;
|
||||
%include "db-symbols.h"
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <stdint.h>
|
||||
#include "thread_dbP.h"
|
||||
#include <tls.h>
|
||||
#include <ldsodefs.h>
|
||||
|
||||
typedef struct pthread pthread;
|
||||
typedef struct pthread_key_struct pthread_key_struct;
|
||||
@@ -37,6 +38,9 @@ typedef struct
|
||||
} dtv;
|
||||
|
||||
typedef struct link_map link_map;
|
||||
typedef struct rtld_global rtld_global;
|
||||
typedef struct dtv_slotinfo_list dtv_slotinfo_list;
|
||||
typedef struct dtv_slotinfo dtv_slotinfo;
|
||||
|
||||
/* Actually static in nptl/init.c, but we only need it for typeof. */
|
||||
extern bool __nptl_initial_report_events;
|
||||
|
||||
@@ -69,7 +69,8 @@ _td_locate_field (td_thragent_t *ta,
|
||||
}
|
||||
}
|
||||
|
||||
if (idx != 0 && idx - (psaddr_t) 0 > DB_DESC_NELEM (desc))
|
||||
if (idx != 0 && DB_DESC_NELEM (desc) != 0
|
||||
&& idx - (psaddr_t) 0 > DB_DESC_NELEM (desc))
|
||||
/* This is an internal indicator to callers with nonzero IDX
|
||||
that the IDX value is too big. */
|
||||
return TD_NOAPLIC;
|
||||
|
||||
@@ -22,6 +22,28 @@
|
||||
# define STRUCTS_DEF_DEFAULTS 1
|
||||
#endif
|
||||
|
||||
#ifndef DB_RTLD_VARIABLE
|
||||
# define DB_RTLD_VARIABLE(name) DB_VARIABLE (name)
|
||||
#endif
|
||||
|
||||
#ifndef DB_MAIN_VARIABLE
|
||||
# define DB_MAIN_VARIABLE(name) DB_VARIABLE (name)
|
||||
#endif
|
||||
|
||||
#ifndef DB_RTLD_GLOBAL_FIELD
|
||||
# if !IS_IN (libpthread)
|
||||
# define DB_RTLD_GLOBAL_FIELD(field) \
|
||||
DB_STRUCT_FIELD (rtld_global, _##field) \
|
||||
DB_MAIN_VARIABLE (_##field)
|
||||
# elif defined SHARED
|
||||
# define DB_RTLD_GLOBAL_FIELD(field) \
|
||||
DB_STRUCT_FIELD (rtld_global, _##field)
|
||||
# else
|
||||
# define DB_RTLD_GLOBAL_FIELD(field) \
|
||||
DB_MAIN_VARIABLE (_##field)
|
||||
# endif
|
||||
#endif /* DB_RTLD_GLOBAL_FIELD */
|
||||
|
||||
DB_STRUCT (pthread)
|
||||
DB_STRUCT_FIELD (pthread, list)
|
||||
DB_STRUCT_FIELD (pthread, report_events)
|
||||
@@ -70,14 +92,31 @@ DB_STRUCT (pthread_key_data_level2)
|
||||
DB_STRUCT_ARRAY_FIELD (pthread_key_data_level2, data)
|
||||
|
||||
DB_STRUCT_FIELD (link_map, l_tls_modid)
|
||||
DB_STRUCT_FIELD (link_map, l_tls_offset)
|
||||
|
||||
DB_STRUCT_ARRAY_FIELD (dtv, dtv)
|
||||
#define pointer_val pointer.val /* Field of anonymous struct in dtv_t. */
|
||||
DB_STRUCT_FIELD (dtv_t, pointer_val)
|
||||
DB_STRUCT_FIELD (dtv_t, counter)
|
||||
#if !IS_IN (libpthread) || TLS_TCB_AT_TP
|
||||
DB_STRUCT_FIELD (pthread, dtvp)
|
||||
#endif
|
||||
|
||||
#if !(IS_IN (libpthread) && !defined SHARED)
|
||||
DB_STRUCT (rtld_global)
|
||||
DB_RTLD_VARIABLE (_rtld_global)
|
||||
#endif
|
||||
DB_RTLD_GLOBAL_FIELD (dl_tls_dtv_slotinfo_list)
|
||||
|
||||
DB_STRUCT (dtv_slotinfo_list)
|
||||
DB_STRUCT_FIELD (dtv_slotinfo_list, len)
|
||||
DB_STRUCT_FIELD (dtv_slotinfo_list, next)
|
||||
DB_STRUCT_ARRAY_FIELD (dtv_slotinfo_list, slotinfo)
|
||||
|
||||
DB_STRUCT (dtv_slotinfo)
|
||||
DB_STRUCT_FIELD (dtv_slotinfo, gen)
|
||||
DB_STRUCT_FIELD (dtv_slotinfo, map)
|
||||
|
||||
#ifdef STRUCTS_DEF_DEFAULTS
|
||||
# undef DB_STRUCT_ARRAY_FIELD
|
||||
# undef DB_ARRAY_VARIABLE
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <assert.h>
|
||||
#include <gnu/lib-names.h>
|
||||
#include "thread_dbP.h"
|
||||
|
||||
static const char *symbol_list_arr[] =
|
||||
@@ -41,12 +40,12 @@ td_symbol_list (void)
|
||||
|
||||
|
||||
ps_err_e
|
||||
td_lookup (struct ps_prochandle *ps, int idx, psaddr_t *sym_addr)
|
||||
td_mod_lookup (struct ps_prochandle *ps, const char *mod,
|
||||
int idx, psaddr_t *sym_addr)
|
||||
{
|
||||
ps_err_e result;
|
||||
assert (idx >= 0 && idx < SYM_NUM_MESSAGES);
|
||||
result = ps_pglobal_lookup (ps, LIBPTHREAD_SO, symbol_list_arr[idx],
|
||||
sym_addr);
|
||||
result = ps_pglobal_lookup (ps, mod, symbol_list_arr[idx], sym_addr);
|
||||
|
||||
#ifdef HAVE_ASM_GLOBAL_DOT_NAME
|
||||
/* For PowerPC, 64-bit uses dot symbols but 32-bit does not.
|
||||
|
||||
+170
-2
@@ -17,14 +17,118 @@
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "thread_dbP.h"
|
||||
#include <link.h>
|
||||
|
||||
/* Get the DTV slotinfo list head entry from the dynamic loader state
|
||||
into *LISTHEAD. */
|
||||
static td_err_e
|
||||
dtv_slotinfo_list (td_thragent_t *ta,
|
||||
psaddr_t *listhead)
|
||||
{
|
||||
td_err_e err;
|
||||
psaddr_t head;
|
||||
|
||||
if (ta->ta_addr__rtld_global == 0
|
||||
&& td_mod_lookup (ta->ph, LD_SO, SYM__rtld_global,
|
||||
&ta->ta_addr__rtld_global) != PS_OK)
|
||||
ta->ta_addr__rtld_global = (void*)-1;
|
||||
|
||||
if (ta->ta_addr__rtld_global != (void*)-1)
|
||||
{
|
||||
err = DB_GET_FIELD (head, ta, ta->ta_addr__rtld_global,
|
||||
rtld_global, _dl_tls_dtv_slotinfo_list, 0);
|
||||
if (err != TD_OK)
|
||||
return err;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ta->ta_addr__dl_tls_dtv_slotinfo_list == 0
|
||||
&& td_mod_lookup (ta->ph, NULL, SYM__dl_tls_dtv_slotinfo_list,
|
||||
&ta->ta_addr__dl_tls_dtv_slotinfo_list) != PS_OK)
|
||||
return TD_ERR;
|
||||
|
||||
err = _td_fetch_value (ta, ta->ta_var__dl_tls_dtv_slotinfo_list,
|
||||
SYM_DESC__dl_tls_dtv_slotinfo_list,
|
||||
0, ta->ta_addr__dl_tls_dtv_slotinfo_list, &head);
|
||||
if (err != TD_OK)
|
||||
return err;
|
||||
}
|
||||
|
||||
*listhead = head;
|
||||
return TD_OK;
|
||||
}
|
||||
|
||||
/* Get the address of the DTV slotinfo entry for MODID into
|
||||
*DTVSLOTINFO. */
|
||||
static td_err_e
|
||||
dtv_slotinfo (td_thragent_t *ta,
|
||||
unsigned long int modid,
|
||||
psaddr_t *dtvslotinfo)
|
||||
{
|
||||
td_err_e err;
|
||||
psaddr_t slot, temp;
|
||||
size_t slbase = 0;
|
||||
|
||||
err = dtv_slotinfo_list (ta, &slot);
|
||||
if (err != TD_OK)
|
||||
return err;
|
||||
|
||||
while (slot)
|
||||
{
|
||||
/* Get the number of entries in this list entry's array. */
|
||||
err = DB_GET_FIELD (temp, ta, slot, dtv_slotinfo_list, len, 0);
|
||||
if (err != TD_OK)
|
||||
return err;
|
||||
size_t len = (uintptr_t)temp;
|
||||
|
||||
/* Did we find the list entry for modid? */
|
||||
if (modid < slbase + len)
|
||||
break;
|
||||
|
||||
/* We didn't, so get the next list entry. */
|
||||
slbase += len;
|
||||
err = DB_GET_FIELD (temp, ta, slot, dtv_slotinfo_list,
|
||||
next, 0);
|
||||
if (err != TD_OK)
|
||||
return err;
|
||||
slot = temp;
|
||||
}
|
||||
|
||||
/* We reached the end of the list and found nothing. */
|
||||
if (!slot)
|
||||
return TD_ERR;
|
||||
|
||||
/* Take the slotinfo for modid from the list entry. */
|
||||
err = DB_GET_FIELD_ADDRESS (temp, ta, slot, dtv_slotinfo_list,
|
||||
slotinfo, modid - slbase);
|
||||
if (err != TD_OK)
|
||||
return err;
|
||||
slot = temp;
|
||||
|
||||
*dtvslotinfo = slot;
|
||||
return TD_OK;
|
||||
}
|
||||
|
||||
/* Return in *BASE the base address of the TLS block for MODID within
|
||||
TH.
|
||||
|
||||
It should return success and yield the correct pointer in any
|
||||
circumstance where the TLS block for the module and thread
|
||||
requested has already been initialized.
|
||||
|
||||
It should fail with TD_TLSDEFER only when the thread could not
|
||||
possibly have observed any values in that TLS block. That way, the
|
||||
debugger can fall back to showing initial values from the PT_TLS
|
||||
segment (and refusing attempts to mutate) for the TD_TLSDEFER case,
|
||||
and never fail to make the values the program will actually see
|
||||
available to the user of the debugger. */
|
||||
td_err_e
|
||||
td_thr_tlsbase (const td_thrhandle_t *th,
|
||||
unsigned long int modid,
|
||||
psaddr_t *base)
|
||||
{
|
||||
td_err_e err;
|
||||
psaddr_t dtv, dtvslot, dtvptr;
|
||||
psaddr_t dtv, dtvslot, dtvptr, temp;
|
||||
|
||||
if (modid < 1)
|
||||
return TD_NOTLS;
|
||||
@@ -50,11 +154,75 @@ td_thr_tlsbase (const td_thrhandle_t *th,
|
||||
return TD_TLSDEFER;
|
||||
}
|
||||
|
||||
err = dtv_slotinfo (th->th_ta_p, modid, &temp);
|
||||
if (err != TD_OK)
|
||||
return err;
|
||||
|
||||
psaddr_t slot;
|
||||
err = DB_GET_STRUCT (slot, th->th_ta_p, temp, dtv_slotinfo);
|
||||
if (err != TD_OK)
|
||||
return err;
|
||||
|
||||
/* Take the link_map from the slotinfo. */
|
||||
psaddr_t map;
|
||||
err = DB_GET_FIELD_LOCAL (map, th->th_ta_p, slot, dtv_slotinfo, map, 0);
|
||||
if (err != TD_OK)
|
||||
return err;
|
||||
if (!map)
|
||||
return TD_ERR;
|
||||
|
||||
/* Ok, the modid is good, now find out what DTV generation it
|
||||
requires. */
|
||||
err = DB_GET_FIELD_LOCAL (temp, th->th_ta_p, slot, dtv_slotinfo, gen, 0);
|
||||
if (err != TD_OK)
|
||||
return err;
|
||||
size_t modgen = (uintptr_t)temp;
|
||||
|
||||
/* Get the DTV pointer from the thread descriptor. */
|
||||
err = DB_GET_FIELD (dtv, th->th_ta_p, pd, pthread, dtvp, 0);
|
||||
if (err != TD_OK)
|
||||
return err;
|
||||
|
||||
psaddr_t dtvgenloc;
|
||||
/* Get the DTV generation count at dtv[0].counter. */
|
||||
err = DB_GET_FIELD_ADDRESS (dtvgenloc, th->th_ta_p, dtv, dtv, dtv, 0);
|
||||
if (err != TD_OK)
|
||||
return err;
|
||||
err = DB_GET_FIELD (temp, th->th_ta_p, dtvgenloc, dtv_t, counter, 0);
|
||||
if (err != TD_OK)
|
||||
return err;
|
||||
size_t dtvgen = (uintptr_t)temp;
|
||||
|
||||
/* Is the DTV current enough? */
|
||||
if (dtvgen < modgen)
|
||||
{
|
||||
try_static_tls:
|
||||
/* If the module uses Static TLS, we're still good. */
|
||||
err = DB_GET_FIELD (temp, th->th_ta_p, map, link_map, l_tls_offset, 0);
|
||||
if (err != TD_OK)
|
||||
return err;
|
||||
ptrdiff_t tlsoff = (uintptr_t)temp;
|
||||
|
||||
if (tlsoff != FORCED_DYNAMIC_TLS_OFFSET
|
||||
&& tlsoff != NO_TLS_OFFSET)
|
||||
{
|
||||
psaddr_t tp = pd;
|
||||
|
||||
#if TLS_TCB_AT_TP
|
||||
dtvptr = tp - tlsoff;
|
||||
#elif TLS_DTV_AT_TP
|
||||
dtvptr = tp + tlsoff + TLS_PRE_TCB_SIZE;
|
||||
#else
|
||||
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
|
||||
#endif
|
||||
|
||||
*base = dtvptr;
|
||||
return TD_OK;
|
||||
}
|
||||
|
||||
return TD_TLSDEFER;
|
||||
}
|
||||
|
||||
/* Find the corresponding entry in the DTV. */
|
||||
err = DB_GET_FIELD_ADDRESS (dtvslot, th->th_ta_p, dtv, dtv, dtv, modid);
|
||||
if (err != TD_OK)
|
||||
@@ -68,7 +236,7 @@ td_thr_tlsbase (const td_thrhandle_t *th,
|
||||
/* It could be that the memory for this module is not allocated for
|
||||
the given thread. */
|
||||
if ((uintptr_t) dtvptr & 1)
|
||||
return TD_TLSDEFER;
|
||||
goto try_static_tls;
|
||||
|
||||
*base = dtvptr;
|
||||
return TD_OK;
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "thread_db.h"
|
||||
#include "../nptl/pthreadP.h" /* This is for *_BITMASK only. */
|
||||
#include <list.h>
|
||||
#include <gnu/lib-names.h>
|
||||
|
||||
/* Indeces for the symbol names. */
|
||||
enum
|
||||
@@ -139,11 +140,11 @@ ta_ok (const td_thragent_t *ta)
|
||||
}
|
||||
|
||||
|
||||
/* Internal wrapper around ps_pglobal_lookup. */
|
||||
extern ps_err_e td_lookup (struct ps_prochandle *ps,
|
||||
int idx, psaddr_t *sym_addr) attribute_hidden;
|
||||
|
||||
|
||||
/* Internal wrappers around ps_pglobal_lookup. */
|
||||
extern ps_err_e td_mod_lookup (struct ps_prochandle *ps, const char *modname,
|
||||
int idx, psaddr_t *sym_addr) attribute_hidden;
|
||||
#define td_lookup(ps, idx, sym_addr) \
|
||||
td_mod_lookup ((ps), LIBPTHREAD_SO, (idx), (sym_addr))
|
||||
|
||||
|
||||
/* Store in psaddr_t VAR the address of inferior's symbol NAME. */
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <selinux/avc.h>
|
||||
#include <selinux/flask.h>
|
||||
#include <selinux/selinux.h>
|
||||
#ifdef HAVE_LIBAUDIT
|
||||
# include <libaudit.h>
|
||||
|
||||
+1
-1
@@ -39,7 +39,7 @@ install-bin := getent makedb
|
||||
makedb-modules = xmalloc hash-string
|
||||
extra-objs += $(makedb-modules:=.o)
|
||||
|
||||
tests = test-netdb tst-nss-test1 test-digits-dots
|
||||
tests = test-netdb tst-nss-test1 test-digits-dots tst-nss-getpwent
|
||||
xtests = bug-erange
|
||||
|
||||
# Specify rules for the nss_* modules. We have some services.
|
||||
|
||||
@@ -134,7 +134,7 @@ CONCAT(_nss_files_set,ENTNAME) (int stayopen)
|
||||
|
||||
__libc_lock_lock (lock);
|
||||
|
||||
status = internal_setent (stayopen);
|
||||
status = internal_setent (1);
|
||||
|
||||
if (status == NSS_STATUS_SUCCESS && fgetpos (stream, &position) < 0)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
/* Copyright (C) 2015 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for 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 <pwd.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int
|
||||
do_test (void)
|
||||
{
|
||||
/* Count the number of entries in the password database, and fetch
|
||||
data from the first and last entries. */
|
||||
size_t count = 0;
|
||||
struct passwd * pw;
|
||||
char *first_name = NULL;
|
||||
uid_t first_uid = 0;
|
||||
char *last_name = NULL;
|
||||
uid_t last_uid = 0;
|
||||
setpwent ();
|
||||
while ((pw = getpwent ()) != NULL)
|
||||
{
|
||||
if (first_name == NULL)
|
||||
{
|
||||
first_name = strdup (pw->pw_name);
|
||||
if (first_name == NULL)
|
||||
{
|
||||
printf ("strdup: %m\n");
|
||||
return 1;
|
||||
}
|
||||
first_uid = pw->pw_uid;
|
||||
}
|
||||
|
||||
free (last_name);
|
||||
last_name = strdup (pw->pw_name);
|
||||
if (last_name == NULL)
|
||||
{
|
||||
printf ("strdup: %m\n");
|
||||
return 1;
|
||||
}
|
||||
last_uid = pw->pw_uid;
|
||||
++count;
|
||||
}
|
||||
endpwent ();
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
printf ("No entries in the password database.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Try again, this time interleaving with name-based and UID-based
|
||||
lookup operations. The counts do not match if the interleaved
|
||||
lookups affected the enumeration. */
|
||||
size_t new_count = 0;
|
||||
setpwent ();
|
||||
while ((pw = getpwent ()) != NULL)
|
||||
{
|
||||
if (new_count == count)
|
||||
{
|
||||
printf ("Additional entry in the password database.\n");
|
||||
return 1;
|
||||
}
|
||||
++new_count;
|
||||
struct passwd *pw2 = getpwnam (first_name);
|
||||
if (pw2 == NULL)
|
||||
{
|
||||
printf ("getpwnam (%s) failed: %m\n", first_name);
|
||||
return 1;
|
||||
}
|
||||
pw2 = getpwnam (last_name);
|
||||
if (pw2 == NULL)
|
||||
{
|
||||
printf ("getpwnam (%s) failed: %m\n", last_name);
|
||||
return 1;
|
||||
}
|
||||
pw2 = getpwuid (first_uid);
|
||||
if (pw2 == NULL)
|
||||
{
|
||||
printf ("getpwuid (%llu) failed: %m\n",
|
||||
(unsigned long long) first_uid);
|
||||
return 1;
|
||||
}
|
||||
pw2 = getpwuid (last_uid);
|
||||
if (pw2 == NULL)
|
||||
{
|
||||
printf ("getpwuid (%llu) failed: %m\n",
|
||||
(unsigned long long) last_uid);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
endpwent ();
|
||||
if (new_count < count)
|
||||
{
|
||||
printf ("Missing entry in the password database.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define TEST_FUNCTION do_test ()
|
||||
#include "../test-skeleton.c"
|
||||
@@ -945,14 +945,13 @@ FCT (pattern, string, string_end, no_leading_period, flags, ends, alloca_used)
|
||||
}
|
||||
else if (c == L('[') && *p == L('.'))
|
||||
{
|
||||
++p;
|
||||
while (1)
|
||||
{
|
||||
c = *++p;
|
||||
if (c == '\0')
|
||||
if (c == L('\0'))
|
||||
return FNM_NOMATCH;
|
||||
|
||||
if (*p == L('.') && p[1] == L(']'))
|
||||
if (c == L('.') && p[1] == L(']'))
|
||||
break;
|
||||
}
|
||||
p += 2;
|
||||
|
||||
+6
-3
@@ -47,7 +47,12 @@ testout=${common_objpfx}posix/globtest-out
|
||||
rm -rf $testdir $testout
|
||||
mkdir $testdir
|
||||
|
||||
trap 'chmod 777 $testdir/noread; rm -fr $testdir $testout' 1 2 3 15
|
||||
cleanup() {
|
||||
chmod 777 $testdir/noread
|
||||
rm -fr $testdir $testout
|
||||
}
|
||||
|
||||
trap cleanup 0 HUP INT QUIT TERM
|
||||
|
||||
echo 1 > $testdir/file1
|
||||
echo 2 > $testdir/file2
|
||||
@@ -795,8 +800,6 @@ if test $failed -ne 0; then
|
||||
fi
|
||||
|
||||
if test $result -eq 0; then
|
||||
chmod 777 $testdir/noread
|
||||
rm -fr $testdir $testout
|
||||
echo "All OK." > $logfile
|
||||
fi
|
||||
|
||||
|
||||
@@ -21,9 +21,11 @@
|
||||
int
|
||||
do_test (void)
|
||||
{
|
||||
const char *pattern = "[[:alpha:]'[:alpha:]\0]";
|
||||
|
||||
return fnmatch (pattern, "a", 0) != FNM_NOMATCH;
|
||||
if (fnmatch ("[[:alpha:]'[:alpha:]\0]", "a", 0) != FNM_NOMATCH)
|
||||
return 1;
|
||||
if (fnmatch ("[a[.\0.]]", "a", 0) != FNM_NOMATCH)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define TEST_FUNCTION do_test ()
|
||||
|
||||
+111
-3
@@ -615,7 +615,8 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
|
||||
int have_to_map = 0;
|
||||
uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data);
|
||||
buffer += pad;
|
||||
if (__glibc_unlikely (buflen < sizeof (struct host_data) + pad))
|
||||
buflen = buflen > pad ? buflen - pad : 0;
|
||||
if (__glibc_unlikely (buflen < sizeof (struct host_data)))
|
||||
{
|
||||
/* The buffer is too small. */
|
||||
too_small:
|
||||
@@ -1031,7 +1032,10 @@ gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname,
|
||||
int h_namelen = 0;
|
||||
|
||||
if (ancount == 0)
|
||||
return NSS_STATUS_NOTFOUND;
|
||||
{
|
||||
*h_errnop = HOST_NOT_FOUND;
|
||||
return NSS_STATUS_NOTFOUND;
|
||||
}
|
||||
|
||||
while (ancount-- > 0 && cp < end_of_message && had_error == 0)
|
||||
{
|
||||
@@ -1208,7 +1212,14 @@ gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname,
|
||||
/* Special case here: if the resolver sent a result but it only
|
||||
contains a CNAME while we are looking for a T_A or T_AAAA record,
|
||||
we fail with NOTFOUND instead of TRYAGAIN. */
|
||||
return canon == NULL ? NSS_STATUS_TRYAGAIN : NSS_STATUS_NOTFOUND;
|
||||
if (canon != NULL)
|
||||
{
|
||||
*h_errnop = HOST_NOT_FOUND;
|
||||
return NSS_STATUS_NOTFOUND;
|
||||
}
|
||||
|
||||
*h_errnop = NETDB_INTERNAL;
|
||||
return NSS_STATUS_TRYAGAIN;
|
||||
}
|
||||
|
||||
|
||||
@@ -1222,11 +1233,101 @@ gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2,
|
||||
|
||||
enum nss_status status = NSS_STATUS_NOTFOUND;
|
||||
|
||||
/* Combining the NSS status of two distinct queries requires some
|
||||
compromise and attention to symmetry (A or AAAA queries can be
|
||||
returned in any order). What follows is a breakdown of how this
|
||||
code is expected to work and why. We discuss only SUCCESS,
|
||||
TRYAGAIN, NOTFOUND and UNAVAIL, since they are the only returns
|
||||
that apply (though RETURN and MERGE exist). We make a distinction
|
||||
between TRYAGAIN (recoverable) and TRYAGAIN' (not-recoverable).
|
||||
A recoverable TRYAGAIN is almost always due to buffer size issues
|
||||
and returns ERANGE in errno and the caller is expected to retry
|
||||
with a larger buffer.
|
||||
|
||||
Lastly, you may be tempted to make significant changes to the
|
||||
conditions in this code to bring about symmetry between responses.
|
||||
Please don't change anything without due consideration for
|
||||
expected application behaviour. Some of the synthesized responses
|
||||
aren't very well thought out and sometimes appear to imply that
|
||||
IPv4 responses are always answer 1, and IPv6 responses are always
|
||||
answer 2, but that's not true (see the implementation of send_dg
|
||||
and send_vc to see response can arrive in any order, particularly
|
||||
for UDP). However, we expect it holds roughly enough of the time
|
||||
that this code works, but certainly needs to be fixed to make this
|
||||
a more robust implementation.
|
||||
|
||||
----------------------------------------------
|
||||
| Answer 1 Status / | Synthesized | Reason |
|
||||
| Answer 2 Status | Status | |
|
||||
|--------------------------------------------|
|
||||
| SUCCESS/SUCCESS | SUCCESS | [1] |
|
||||
| SUCCESS/TRYAGAIN | TRYAGAIN | [5] |
|
||||
| SUCCESS/TRYAGAIN' | SUCCESS | [1] |
|
||||
| SUCCESS/NOTFOUND | SUCCESS | [1] |
|
||||
| SUCCESS/UNAVAIL | SUCCESS | [1] |
|
||||
| TRYAGAIN/SUCCESS | TRYAGAIN | [2] |
|
||||
| TRYAGAIN/TRYAGAIN | TRYAGAIN | [2] |
|
||||
| TRYAGAIN/TRYAGAIN' | TRYAGAIN | [2] |
|
||||
| TRYAGAIN/NOTFOUND | TRYAGAIN | [2] |
|
||||
| TRYAGAIN/UNAVAIL | TRYAGAIN | [2] |
|
||||
| TRYAGAIN'/SUCCESS | SUCCESS | [3] |
|
||||
| TRYAGAIN'/TRYAGAIN | TRYAGAIN | [3] |
|
||||
| TRYAGAIN'/TRYAGAIN' | TRYAGAIN' | [3] |
|
||||
| TRYAGAIN'/NOTFOUND | TRYAGAIN' | [3] |
|
||||
| TRYAGAIN'/UNAVAIL | UNAVAIL | [3] |
|
||||
| NOTFOUND/SUCCESS | SUCCESS | [3] |
|
||||
| NOTFOUND/TRYAGAIN | TRYAGAIN | [3] |
|
||||
| NOTFOUND/TRYAGAIN' | TRYAGAIN' | [3] |
|
||||
| NOTFOUND/NOTFOUND | NOTFOUND | [3] |
|
||||
| NOTFOUND/UNAVAIL | UNAVAIL | [3] |
|
||||
| UNAVAIL/SUCCESS | UNAVAIL | [4] |
|
||||
| UNAVAIL/TRYAGAIN | UNAVAIL | [4] |
|
||||
| UNAVAIL/TRYAGAIN' | UNAVAIL | [4] |
|
||||
| UNAVAIL/NOTFOUND | UNAVAIL | [4] |
|
||||
| UNAVAIL/UNAVAIL | UNAVAIL | [4] |
|
||||
----------------------------------------------
|
||||
|
||||
[1] If the first response is a success we return success.
|
||||
This ignores the state of the second answer and in fact
|
||||
incorrectly sets errno and h_errno to that of the second
|
||||
answer. However because the response is a success we ignore
|
||||
*errnop and *h_errnop (though that means you touched errno on
|
||||
success). We are being conservative here and returning the
|
||||
likely IPv4 response in the first answer as a success.
|
||||
|
||||
[2] If the first response is a recoverable TRYAGAIN we return
|
||||
that instead of looking at the second response. The
|
||||
expectation here is that we have failed to get an IPv4 response
|
||||
and should retry both queries.
|
||||
|
||||
[3] If the first response was not a SUCCESS and the second
|
||||
response is not NOTFOUND (had a SUCCESS, need to TRYAGAIN,
|
||||
or failed entirely e.g. TRYAGAIN' and UNAVAIL) then use the
|
||||
result from the second response, otherwise the first responses
|
||||
status is used. Again we have some odd side-effects when the
|
||||
second response is NOTFOUND because we overwrite *errnop and
|
||||
*h_errnop that means that a first answer of NOTFOUND might see
|
||||
its *errnop and *h_errnop values altered. Whether it matters
|
||||
in practice that a first response NOTFOUND has the wrong
|
||||
*errnop and *h_errnop is undecided.
|
||||
|
||||
[4] If the first response is UNAVAIL we return that instead of
|
||||
looking at the second response. The expectation here is that
|
||||
it will have failed similarly e.g. configuration failure.
|
||||
|
||||
[5] Testing this code is complicated by the fact that truncated
|
||||
second response buffers might be returned as SUCCESS if the
|
||||
first answer is a SUCCESS. To fix this we add symmetry to
|
||||
TRYAGAIN with the second response. If the second response
|
||||
is a recoverable error we now return TRYAGIN even if the first
|
||||
response was SUCCESS. */
|
||||
|
||||
if (anslen1 > 0)
|
||||
status = gaih_getanswer_slice(answer1, anslen1, qname,
|
||||
&pat, &buffer, &buflen,
|
||||
errnop, h_errnop, ttlp,
|
||||
&first);
|
||||
|
||||
if ((status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND
|
||||
|| (status == NSS_STATUS_TRYAGAIN
|
||||
/* We want to look at the second answer in case of an
|
||||
@@ -1242,8 +1343,15 @@ gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2,
|
||||
&pat, &buffer, &buflen,
|
||||
errnop, h_errnop, ttlp,
|
||||
&first);
|
||||
/* Use the second response status in some cases. */
|
||||
if (status != NSS_STATUS_SUCCESS && status2 != NSS_STATUS_NOTFOUND)
|
||||
status = status2;
|
||||
/* Do not return a truncated second response (unless it was
|
||||
unavoidable e.g. unrecoverable TRYAGAIN). */
|
||||
if (status == NSS_STATUS_SUCCESS
|
||||
&& (status2 == NSS_STATUS_TRYAGAIN
|
||||
&& *errnop == ERANGE && *h_errnop != NO_RECOVERY))
|
||||
status = NSS_STATUS_TRYAGAIN;
|
||||
}
|
||||
|
||||
return status;
|
||||
|
||||
@@ -396,6 +396,7 @@ __libc_res_nsearch(res_state statp,
|
||||
{
|
||||
free (*answerp2);
|
||||
*answerp2 = NULL;
|
||||
*nanswerp2 = 0;
|
||||
*answerp2_malloced = 0;
|
||||
}
|
||||
}
|
||||
@@ -447,6 +448,7 @@ __libc_res_nsearch(res_state statp,
|
||||
{
|
||||
free (*answerp2);
|
||||
*answerp2 = NULL;
|
||||
*nanswerp2 = 0;
|
||||
*answerp2_malloced = 0;
|
||||
}
|
||||
|
||||
@@ -521,6 +523,7 @@ __libc_res_nsearch(res_state statp,
|
||||
{
|
||||
free (*answerp2);
|
||||
*answerp2 = NULL;
|
||||
*nanswerp2 = 0;
|
||||
*answerp2_malloced = 0;
|
||||
}
|
||||
if (saved_herrno != -1)
|
||||
|
||||
+197
-67
@@ -1,3 +1,20 @@
|
||||
/* Copyright (C) 2016 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1985, 1989, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
@@ -361,6 +378,8 @@ __libc_res_nsend(res_state statp, const u_char *buf, int buflen,
|
||||
#ifdef USE_HOOKS
|
||||
if (__glibc_unlikely (statp->qhook || statp->rhook)) {
|
||||
if (anssiz < MAXPACKET && ansp) {
|
||||
/* Always allocate MAXPACKET, callers expect
|
||||
this specific size. */
|
||||
u_char *buf = malloc (MAXPACKET);
|
||||
if (buf == NULL)
|
||||
return (-1);
|
||||
@@ -660,6 +679,77 @@ libresolv_hidden_def (res_nsend)
|
||||
|
||||
/* Private */
|
||||
|
||||
/* The send_vc function is responsible for sending a DNS query over TCP
|
||||
to the nameserver numbered NS from the res_state STATP i.e.
|
||||
EXT(statp).nssocks[ns]. The function supports sending both IPv4 and
|
||||
IPv6 queries at the same serially on the same socket.
|
||||
|
||||
Please note that for TCP there is no way to disable sending both
|
||||
queries, unlike UDP, which honours RES_SNGLKUP and RES_SNGLKUPREOP
|
||||
and sends the queries serially and waits for the result after each
|
||||
sent query. This implemetnation should be corrected to honour these
|
||||
options.
|
||||
|
||||
Please also note that for TCP we send both queries over the same
|
||||
socket one after another. This technically violates best practice
|
||||
since the server is allowed to read the first query, respond, and
|
||||
then close the socket (to service another client). If the server
|
||||
does this, then the remaining second query in the socket data buffer
|
||||
will cause the server to send the client an RST which will arrive
|
||||
asynchronously and the client's OS will likely tear down the socket
|
||||
receive buffer resulting in a potentially short read and lost
|
||||
response data. This will force the client to retry the query again,
|
||||
and this process may repeat until all servers and connection resets
|
||||
are exhausted and then the query will fail. It's not known if this
|
||||
happens with any frequency in real DNS server implementations. This
|
||||
implementation should be corrected to use two sockets by default for
|
||||
parallel queries.
|
||||
|
||||
The query stored in BUF of BUFLEN length is sent first followed by
|
||||
the query stored in BUF2 of BUFLEN2 length. Queries are sent
|
||||
serially on the same socket.
|
||||
|
||||
Answers to the query are stored firstly in *ANSP up to a max of
|
||||
*ANSSIZP bytes. If more than *ANSSIZP bytes are needed and ANSCP
|
||||
is non-NULL (to indicate that modifying the answer buffer is allowed)
|
||||
then malloc is used to allocate a new response buffer and ANSCP and
|
||||
ANSP will both point to the new buffer. If more than *ANSSIZP bytes
|
||||
are needed but ANSCP is NULL, then as much of the response as
|
||||
possible is read into the buffer, but the results will be truncated.
|
||||
When truncation happens because of a small answer buffer the DNS
|
||||
packets header field TC will bet set to 1, indicating a truncated
|
||||
message and the rest of the socket data will be read and discarded.
|
||||
|
||||
Answers to the query are stored secondly in *ANSP2 up to a max of
|
||||
*ANSSIZP2 bytes, with the actual response length stored in
|
||||
*RESPLEN2. If more than *ANSSIZP bytes are needed and ANSP2
|
||||
is non-NULL (required for a second query) then malloc is used to
|
||||
allocate a new response buffer, *ANSSIZP2 is set to the new buffer
|
||||
size and *ANSP2_MALLOCED is set to 1.
|
||||
|
||||
The ANSP2_MALLOCED argument will eventually be removed as the
|
||||
change in buffer pointer can be used to detect the buffer has
|
||||
changed and that the caller should use free on the new buffer.
|
||||
|
||||
Note that the answers may arrive in any order from the server and
|
||||
therefore the first and second answer buffers may not correspond to
|
||||
the first and second queries.
|
||||
|
||||
It is not supported to call this function with a non-NULL ANSP2
|
||||
but a NULL ANSCP. Put another way, you can call send_vc with a
|
||||
single unmodifiable buffer or two modifiable buffers, but no other
|
||||
combination is supported.
|
||||
|
||||
It is the caller's responsibility to free the malloc allocated
|
||||
buffers by detecting that the pointers have changed from their
|
||||
original values i.e. *ANSCP or *ANSP2 has changed.
|
||||
|
||||
If errors are encountered then *TERRNO is set to an appropriate
|
||||
errno value and a zero result is returned for a recoverable error,
|
||||
and a less-than zero result is returned for a non-recoverable error.
|
||||
|
||||
If no errors are encountered then *TERRNO is left unmodified and
|
||||
a the length of the first response in bytes is returned. */
|
||||
static int
|
||||
send_vc(res_state statp,
|
||||
const u_char *buf, int buflen, const u_char *buf2, int buflen2,
|
||||
@@ -669,11 +759,7 @@ send_vc(res_state statp,
|
||||
{
|
||||
const HEADER *hp = (HEADER *) buf;
|
||||
const HEADER *hp2 = (HEADER *) buf2;
|
||||
u_char *ans = *ansp;
|
||||
int orig_anssizp = *anssizp;
|
||||
// XXX REMOVE
|
||||
// int anssiz = *anssizp;
|
||||
HEADER *anhp = (HEADER *) ans;
|
||||
HEADER *anhp = (HEADER *) *ansp;
|
||||
struct sockaddr_in6 *nsap = EXT(statp).nsaddrs[ns];
|
||||
int truncating, connreset, n;
|
||||
/* On some architectures compiler might emit a warning indicating
|
||||
@@ -766,6 +852,8 @@ send_vc(res_state statp,
|
||||
* Receive length & response
|
||||
*/
|
||||
int recvresp1 = 0;
|
||||
/* Skip the second response if there is no second query.
|
||||
To do that we mark the second response as received. */
|
||||
int recvresp2 = buf2 == NULL;
|
||||
uint16_t rlen16;
|
||||
read_len:
|
||||
@@ -802,40 +890,14 @@ send_vc(res_state statp,
|
||||
u_char **thisansp;
|
||||
int *thisresplenp;
|
||||
if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) {
|
||||
/* We have not received any responses
|
||||
yet or we only have one response to
|
||||
receive. */
|
||||
thisanssizp = anssizp;
|
||||
thisansp = anscp ?: ansp;
|
||||
assert (anscp != NULL || ansp2 == NULL);
|
||||
thisresplenp = &resplen;
|
||||
} else {
|
||||
if (*anssizp != MAXPACKET) {
|
||||
/* No buffer allocated for the first
|
||||
reply. We can try to use the rest
|
||||
of the user-provided buffer. */
|
||||
#if __GNUC_PREREQ (4, 7)
|
||||
DIAG_PUSH_NEEDS_COMMENT;
|
||||
DIAG_IGNORE_NEEDS_COMMENT (5, "-Wmaybe-uninitialized");
|
||||
#endif
|
||||
#if _STRING_ARCH_unaligned
|
||||
*anssizp2 = orig_anssizp - resplen;
|
||||
*ansp2 = *ansp + resplen;
|
||||
#else
|
||||
int aligned_resplen
|
||||
= ((resplen + __alignof__ (HEADER) - 1)
|
||||
& ~(__alignof__ (HEADER) - 1));
|
||||
*anssizp2 = orig_anssizp - aligned_resplen;
|
||||
*ansp2 = *ansp + aligned_resplen;
|
||||
#endif
|
||||
#if __GNUC_PREREQ (4, 7)
|
||||
DIAG_POP_NEEDS_COMMENT;
|
||||
#endif
|
||||
} else {
|
||||
/* The first reply did not fit into the
|
||||
user-provided buffer. Maybe the second
|
||||
answer will. */
|
||||
*anssizp2 = orig_anssizp;
|
||||
*ansp2 = *ansp;
|
||||
}
|
||||
|
||||
thisanssizp = anssizp2;
|
||||
thisansp = ansp2;
|
||||
thisresplenp = resplen2;
|
||||
@@ -843,10 +905,14 @@ send_vc(res_state statp,
|
||||
anhp = (HEADER *) *thisansp;
|
||||
|
||||
*thisresplenp = rlen;
|
||||
if (rlen > *thisanssizp) {
|
||||
/* Yes, we test ANSCP here. If we have two buffers
|
||||
both will be allocatable. */
|
||||
if (__glibc_likely (anscp != NULL)) {
|
||||
/* Is the answer buffer too small? */
|
||||
if (*thisanssizp < rlen) {
|
||||
/* If the current buffer is not the the static
|
||||
user-supplied buffer then we can reallocate
|
||||
it. */
|
||||
if (thisansp != NULL && thisansp != ansp) {
|
||||
/* Always allocate MAXPACKET, callers expect
|
||||
this specific size. */
|
||||
u_char *newp = malloc (MAXPACKET);
|
||||
if (newp == NULL) {
|
||||
*terrno = ENOMEM;
|
||||
@@ -858,6 +924,9 @@ send_vc(res_state statp,
|
||||
if (thisansp == ansp2)
|
||||
*ansp2_malloced = 1;
|
||||
anhp = (HEADER *) newp;
|
||||
/* A uint16_t can't be larger than MAXPACKET
|
||||
thus it's safe to allocate MAXPACKET but
|
||||
read RLEN bytes instead. */
|
||||
len = rlen;
|
||||
} else {
|
||||
Dprint(statp->options & RES_DEBUG,
|
||||
@@ -1021,6 +1090,66 @@ reopen (res_state statp, int *terrno, int ns)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* The send_dg function is responsible for sending a DNS query over UDP
|
||||
to the nameserver numbered NS from the res_state STATP i.e.
|
||||
EXT(statp).nssocks[ns]. The function supports IPv4 and IPv6 queries
|
||||
along with the ability to send the query in parallel for both stacks
|
||||
(default) or serially (RES_SINGLKUP). It also supports serial lookup
|
||||
with a close and reopen of the socket used to talk to the server
|
||||
(RES_SNGLKUPREOP) to work around broken name servers.
|
||||
|
||||
The query stored in BUF of BUFLEN length is sent first followed by
|
||||
the query stored in BUF2 of BUFLEN2 length. Queries are sent
|
||||
in parallel (default) or serially (RES_SINGLKUP or RES_SNGLKUPREOP).
|
||||
|
||||
Answers to the query are stored firstly in *ANSP up to a max of
|
||||
*ANSSIZP bytes. If more than *ANSSIZP bytes are needed and ANSCP
|
||||
is non-NULL (to indicate that modifying the answer buffer is allowed)
|
||||
then malloc is used to allocate a new response buffer and ANSCP and
|
||||
ANSP will both point to the new buffer. If more than *ANSSIZP bytes
|
||||
are needed but ANSCP is NULL, then as much of the response as
|
||||
possible is read into the buffer, but the results will be truncated.
|
||||
When truncation happens because of a small answer buffer the DNS
|
||||
packets header field TC will bet set to 1, indicating a truncated
|
||||
message, while the rest of the UDP packet is discarded.
|
||||
|
||||
Answers to the query are stored secondly in *ANSP2 up to a max of
|
||||
*ANSSIZP2 bytes, with the actual response length stored in
|
||||
*RESPLEN2. If more than *ANSSIZP bytes are needed and ANSP2
|
||||
is non-NULL (required for a second query) then malloc is used to
|
||||
allocate a new response buffer, *ANSSIZP2 is set to the new buffer
|
||||
size and *ANSP2_MALLOCED is set to 1.
|
||||
|
||||
The ANSP2_MALLOCED argument will eventually be removed as the
|
||||
change in buffer pointer can be used to detect the buffer has
|
||||
changed and that the caller should use free on the new buffer.
|
||||
|
||||
Note that the answers may arrive in any order from the server and
|
||||
therefore the first and second answer buffers may not correspond to
|
||||
the first and second queries.
|
||||
|
||||
It is not supported to call this function with a non-NULL ANSP2
|
||||
but a NULL ANSCP. Put another way, you can call send_vc with a
|
||||
single unmodifiable buffer or two modifiable buffers, but no other
|
||||
combination is supported.
|
||||
|
||||
It is the caller's responsibility to free the malloc allocated
|
||||
buffers by detecting that the pointers have changed from their
|
||||
original values i.e. *ANSCP or *ANSP2 has changed.
|
||||
|
||||
If an answer is truncated because of UDP datagram DNS limits then
|
||||
*V_CIRCUIT is set to 1 and the return value non-zero to indicate to
|
||||
the caller to retry with TCP. The value *GOTSOMEWHERE is set to 1
|
||||
if any progress was made reading a response from the nameserver and
|
||||
is used by the caller to distinguish between ECONNREFUSED and
|
||||
ETIMEDOUT (the latter if *GOTSOMEWHERE is 1).
|
||||
|
||||
If errors are encountered then *TERRNO is set to an appropriate
|
||||
errno value and a zero result is returned for a recoverable error,
|
||||
and a less-than zero result is returned for a non-recoverable error.
|
||||
|
||||
If no errors are encountered then *TERRNO is left unmodified and
|
||||
a the length of the first response in bytes is returned. */
|
||||
static int
|
||||
send_dg(res_state statp,
|
||||
const u_char *buf, int buflen, const u_char *buf2, int buflen2,
|
||||
@@ -1030,8 +1159,6 @@ send_dg(res_state statp,
|
||||
{
|
||||
const HEADER *hp = (HEADER *) buf;
|
||||
const HEADER *hp2 = (HEADER *) buf2;
|
||||
u_char *ans = *ansp;
|
||||
int orig_anssizp = *anssizp;
|
||||
struct timespec now, timeout, finish;
|
||||
struct pollfd pfd[1];
|
||||
int ptimeout;
|
||||
@@ -1064,6 +1191,8 @@ send_dg(res_state statp,
|
||||
int need_recompute = 0;
|
||||
int nwritten = 0;
|
||||
int recvresp1 = 0;
|
||||
/* Skip the second response if there is no second query.
|
||||
To do that we mark the second response as received. */
|
||||
int recvresp2 = buf2 == NULL;
|
||||
pfd[0].fd = EXT(statp).nssocks[ns];
|
||||
pfd[0].events = POLLOUT;
|
||||
@@ -1227,55 +1356,56 @@ send_dg(res_state statp,
|
||||
int *thisresplenp;
|
||||
|
||||
if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) {
|
||||
/* We have not received any responses
|
||||
yet or we only have one response to
|
||||
receive. */
|
||||
thisanssizp = anssizp;
|
||||
thisansp = anscp ?: ansp;
|
||||
assert (anscp != NULL || ansp2 == NULL);
|
||||
thisresplenp = &resplen;
|
||||
} else {
|
||||
if (*anssizp != MAXPACKET) {
|
||||
/* No buffer allocated for the first
|
||||
reply. We can try to use the rest
|
||||
of the user-provided buffer. */
|
||||
#if _STRING_ARCH_unaligned
|
||||
*anssizp2 = orig_anssizp - resplen;
|
||||
*ansp2 = *ansp + resplen;
|
||||
#else
|
||||
int aligned_resplen
|
||||
= ((resplen + __alignof__ (HEADER) - 1)
|
||||
& ~(__alignof__ (HEADER) - 1));
|
||||
*anssizp2 = orig_anssizp - aligned_resplen;
|
||||
*ansp2 = *ansp + aligned_resplen;
|
||||
#endif
|
||||
} else {
|
||||
/* The first reply did not fit into the
|
||||
user-provided buffer. Maybe the second
|
||||
answer will. */
|
||||
*anssizp2 = orig_anssizp;
|
||||
*ansp2 = *ansp;
|
||||
}
|
||||
|
||||
thisanssizp = anssizp2;
|
||||
thisansp = ansp2;
|
||||
thisresplenp = resplen2;
|
||||
}
|
||||
|
||||
if (*thisanssizp < MAXPACKET
|
||||
/* Yes, we test ANSCP here. If we have two buffers
|
||||
both will be allocatable. */
|
||||
&& anscp
|
||||
/* If the current buffer is not the the static
|
||||
user-supplied buffer then we can reallocate
|
||||
it. */
|
||||
&& (thisansp != NULL && thisansp != ansp)
|
||||
#ifdef FIONREAD
|
||||
/* Is the size too small? */
|
||||
&& (ioctl (pfd[0].fd, FIONREAD, thisresplenp) < 0
|
||||
|| *thisanssizp < *thisresplenp)
|
||||
#endif
|
||||
) {
|
||||
/* Always allocate MAXPACKET, callers expect
|
||||
this specific size. */
|
||||
u_char *newp = malloc (MAXPACKET);
|
||||
if (newp != NULL) {
|
||||
*anssizp = MAXPACKET;
|
||||
*thisansp = ans = newp;
|
||||
*thisanssizp = MAXPACKET;
|
||||
*thisansp = newp;
|
||||
if (thisansp == ansp2)
|
||||
*ansp2_malloced = 1;
|
||||
}
|
||||
}
|
||||
/* We could end up with truncation if anscp was NULL
|
||||
(not allowed to change caller's buffer) and the
|
||||
response buffer size is too small. This isn't a
|
||||
reliable way to detect truncation because the ioctl
|
||||
may be an inaccurate report of the UDP message size.
|
||||
Therefore we use this only to issue debug output.
|
||||
To do truncation accurately with UDP we need
|
||||
MSG_TRUNC which is only available on Linux. We
|
||||
can abstract out the Linux-specific feature in the
|
||||
future to detect truncation. */
|
||||
if (__glibc_unlikely (*thisanssizp < *thisresplenp)) {
|
||||
Dprint(statp->options & RES_DEBUG,
|
||||
(stdout, ";; response may be truncated (UDP)\n")
|
||||
);
|
||||
}
|
||||
|
||||
HEADER *anhp = (HEADER *) *thisansp;
|
||||
socklen_t fromlen = sizeof(struct sockaddr_in6);
|
||||
assert (sizeof(from) <= fromlen);
|
||||
|
||||
@@ -3,9 +3,14 @@
|
||||
# Each line is either a comment starting with # or it looks like:
|
||||
# libfoo.so: function
|
||||
# or
|
||||
# libfoo.so: function + {RELA|REL} RELOC
|
||||
# or
|
||||
# libfoo.so: function ?
|
||||
# The latter means that a PLT entry for function is optional in libfoo.so.
|
||||
# The former means one is required.
|
||||
# The first entry means that one is required.
|
||||
# The second entry means that one is required and relocation may also be
|
||||
# {RELA|REL} RELOC.
|
||||
# The third entry means that a PLT entry for function is optional in
|
||||
# libfoo.so.
|
||||
# The second file argument is - and this (stdin) receives the output
|
||||
# of the check-localplt program.
|
||||
|
||||
@@ -14,7 +19,10 @@ BEGIN { result = 0 }
|
||||
FILENAME != "-" && /^#/ { next }
|
||||
|
||||
FILENAME != "-" {
|
||||
if (NF != 2 && !(NF == 3 && $3 == "?")) {
|
||||
if (NF == 5 && $3 == "+" && ($4 == "RELA" || $4 == "REL")) {
|
||||
accept_type[$1 " " $2] = $4;
|
||||
accept_reloc[$1 " " $2] = $5;
|
||||
} else if (NF != 2 && !(NF == 3 && $3 == "?")) {
|
||||
printf "%s:%d: bad data line: %s\n", FILENAME, FNR, $0 > "/dev/stderr";
|
||||
result = 2;
|
||||
} else {
|
||||
@@ -23,7 +31,7 @@ FILENAME != "-" {
|
||||
next;
|
||||
}
|
||||
|
||||
NF != 2 {
|
||||
NF != 2 && !(NF == 4 && ($3 == "RELA" || $3 == "REL")) {
|
||||
print "Unexpected output from check-localplt:", $0 > "/dev/stderr";
|
||||
result = 2;
|
||||
next
|
||||
@@ -31,7 +39,23 @@ NF != 2 {
|
||||
|
||||
{
|
||||
key = $1 " " $2
|
||||
if (key in accept) {
|
||||
if ($3 == "RELA" || $3 == "REL") {
|
||||
# Entries like:
|
||||
# libc.so: free + RELA R_X86_64_GLOB_DAT
|
||||
# may be ignored.
|
||||
if (key in accept_type && accept_type[key] == $3 && accept_reloc[key] == $4) {
|
||||
# Match
|
||||
# libc.so: free + RELA R_X86_64_GLOB_DAT
|
||||
delete accept_type[key]
|
||||
}
|
||||
} else if (NF == 2 && key in accept_reloc) {
|
||||
# Match
|
||||
# libc.so: free
|
||||
# against
|
||||
# libc.so: free + RELA R_X86_64_GLOB_DAT
|
||||
if (key in accept_type)
|
||||
delete accept_type[key]
|
||||
} else if (key in accept) {
|
||||
delete accept[key]
|
||||
} else {
|
||||
print "Extra PLT reference:", $0;
|
||||
@@ -49,5 +73,11 @@ END {
|
||||
}
|
||||
}
|
||||
|
||||
for (key in accept_type) {
|
||||
# It's mandatory.
|
||||
print "Missing required PLT or " accept_reloc[key] " reference:", key;
|
||||
result = 1;
|
||||
}
|
||||
|
||||
exit(result);
|
||||
}
|
||||
|
||||
+49
-2
@@ -13,6 +13,8 @@ FILENAME != lastfile {
|
||||
}
|
||||
lastfile = FILENAME;
|
||||
jmprel_offset = 0;
|
||||
rela_offset = 0;
|
||||
rel_offset = 0;
|
||||
delete section_offset_by_address;
|
||||
}
|
||||
|
||||
@@ -35,11 +37,35 @@ in_relocs && relocs_offset == jmprel_offset && NF >= 5 {
|
||||
# Relocations against GNU_IFUNC symbols are not shown as an hexadecimal
|
||||
# value, but rather as the resolver symbol followed by ().
|
||||
if ($4 ~ /\(\)/) {
|
||||
print whatfile, $5
|
||||
print whatfile, gensub(/@.*/, "", "g", $5)
|
||||
} else {
|
||||
symval = strtonum("0x" $4);
|
||||
if (symval != 0)
|
||||
print whatfile, $5
|
||||
print whatfile, gensub(/@.*/, "", "g", $5)
|
||||
}
|
||||
}
|
||||
|
||||
in_relocs && relocs_offset == rela_offset && NF >= 5 {
|
||||
# Relocations against GNU_IFUNC symbols are not shown as an hexadecimal
|
||||
# value, but rather as the resolver symbol followed by ().
|
||||
if ($4 ~ /\(\)/) {
|
||||
print whatfile, gensub(/@.*/, "", "g", $5), "RELA", $3
|
||||
} else {
|
||||
symval = strtonum("0x" $4);
|
||||
if (symval != 0)
|
||||
print whatfile, gensub(/@.*/, "", "g", $5), "RELA", $3
|
||||
}
|
||||
}
|
||||
|
||||
in_relocs && relocs_offset == rel_offset && NF >= 5 {
|
||||
# Relocations against GNU_IFUNC symbols are not shown as an hexadecimal
|
||||
# value, but rather as the resolver symbol followed by ().
|
||||
if ($4 ~ /\(\)/) {
|
||||
print whatfile, gensub(/@.*/, "", "g", $5), "REL", $3
|
||||
} else {
|
||||
symval = strtonum("0x" $4);
|
||||
if (symval != 0)
|
||||
print whatfile, gensub(/@.*/, "", "g", $5), "REL", $3
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,4 +88,25 @@ $2 == "(JMPREL)" {
|
||||
next
|
||||
}
|
||||
|
||||
$2 == "(RELA)" {
|
||||
rela_addr = strtonum($3);
|
||||
if (rela_addr in section_offset_by_address) {
|
||||
rela_offset = section_offset_by_address[rela_addr];
|
||||
} else {
|
||||
print FILENAME ": *** DT_RELA does not match any section's address";
|
||||
result = 2;
|
||||
}
|
||||
next
|
||||
}
|
||||
|
||||
$2 == "(REL)" {
|
||||
rel_addr = strtonum($3);
|
||||
if (rel_addr in section_offset_by_address) {
|
||||
rel_offset = section_offset_by_address[rel_addr];
|
||||
} else {
|
||||
print FILENAME ": *** DT_REL does not match any section's address";
|
||||
result = 2;
|
||||
}
|
||||
next
|
||||
}
|
||||
END { exit(result) }
|
||||
|
||||
+7
-5
@@ -66,11 +66,11 @@ test-srcs := tst-fmtmsg
|
||||
tests := tst-strtol tst-strtod testmb testrand testsort testdiv \
|
||||
test-canon test-canon2 tst-strtoll tst-environ \
|
||||
tst-xpg-basename tst-random tst-random2 tst-bsearch \
|
||||
tst-limits tst-rand48 bug-strtod tst-setcontext \
|
||||
test-a64l tst-qsort tst-system testmb2 bug-strtod2 \
|
||||
tst-atof1 tst-atof2 tst-strtod2 tst-strtod3 tst-rand48-2 \
|
||||
tst-makecontext tst-strtod4 tst-strtod5 tst-qsort2 \
|
||||
tst-makecontext2 tst-strtod6 tst-unsetenv1 \
|
||||
tst-limits tst-rand48 bug-strtod tst-setcontext \
|
||||
tst-setcontext2 test-a64l tst-qsort tst-system testmb2 \
|
||||
bug-strtod2 tst-atof1 tst-atof2 tst-strtod2 tst-strtod3 \
|
||||
tst-rand48-2 tst-makecontext tst-strtod4 tst-strtod5 \
|
||||
tst-qsort2 tst-makecontext2 tst-strtod6 tst-unsetenv1 \
|
||||
tst-makecontext3 bug-getcontext bug-fmtmsg1 \
|
||||
tst-secure-getenv tst-strtod-overflow tst-strtod-round \
|
||||
tst-tininess tst-strtod-underflow tst-tls-atexit
|
||||
@@ -157,3 +157,5 @@ tst-tls-atexit-lib.so-no-z-defs = yes
|
||||
|
||||
$(objpfx)tst-tls-atexit: $(shared-thread-library) $(libdl)
|
||||
$(objpfx)tst-tls-atexit.out: $(objpfx)tst-tls-atexit-lib.so
|
||||
|
||||
$(objpfx)tst-makecontext: $(libdl)
|
||||
|
||||
+13
-11
@@ -269,18 +269,20 @@ unsetenv (name)
|
||||
ep = __environ;
|
||||
if (ep != NULL)
|
||||
while (*ep != NULL)
|
||||
if (!strncmp (*ep, name, len) && (*ep)[len] == '=')
|
||||
{
|
||||
/* Found it. Remove this pointer by moving later ones back. */
|
||||
char **dp = ep;
|
||||
{
|
||||
if (!strncmp (*ep, name, len) && (*ep)[len] == '=')
|
||||
{
|
||||
/* Found it. Remove this pointer by moving later ones back. */
|
||||
char **dp = ep;
|
||||
|
||||
do
|
||||
dp[0] = dp[1];
|
||||
while (*dp++);
|
||||
/* Continue the loop in case NAME appears again. */
|
||||
}
|
||||
else
|
||||
++ep;
|
||||
do
|
||||
dp[0] = dp[1];
|
||||
while (*dp++);
|
||||
/* Continue the loop in case NAME appears again. */
|
||||
}
|
||||
else
|
||||
++ep;
|
||||
}
|
||||
|
||||
UNLOCK;
|
||||
|
||||
|
||||
@@ -19,23 +19,62 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <ucontext.h>
|
||||
#include <assert.h>
|
||||
#include <unwind.h>
|
||||
#include <dlfcn.h>
|
||||
#include <gnu/lib-names.h>
|
||||
|
||||
ucontext_t ucp;
|
||||
char st1[8192];
|
||||
char st1[16384];
|
||||
__thread int thr;
|
||||
|
||||
int somevar = -76;
|
||||
long othervar = -78L;
|
||||
|
||||
struct trace_arg
|
||||
{
|
||||
int cnt, size;
|
||||
};
|
||||
|
||||
static _Unwind_Reason_Code
|
||||
backtrace_helper (struct _Unwind_Context *ctx, void *a)
|
||||
{
|
||||
struct trace_arg *arg = a;
|
||||
if (++arg->cnt == arg->size)
|
||||
return _URC_END_OF_STACK;
|
||||
return _URC_NO_REASON;
|
||||
}
|
||||
|
||||
void
|
||||
cf (int i)
|
||||
{
|
||||
struct trace_arg arg = { .size = 100, .cnt = -1 };
|
||||
void *handle;
|
||||
_Unwind_Reason_Code (*unwind_backtrace) (_Unwind_Trace_Fn, void *);
|
||||
|
||||
if (i != othervar || thr != 94)
|
||||
{
|
||||
printf ("i %d thr %d\n", i, thr);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/* Test if callback function of _Unwind_Backtrace is not called infinitely
|
||||
times. See Bug 18508 or gcc bug "Bug 66303 - runtime.Caller() returns
|
||||
infinitely deep stack frames on s390x.".
|
||||
The go runtime calls backtrace_full() in
|
||||
<gcc-src>/libbacktrace/backtrace.c, which uses _Unwind_Backtrace(). */
|
||||
handle = dlopen (LIBGCC_S_SO, RTLD_LAZY);
|
||||
if (handle != NULL)
|
||||
{
|
||||
unwind_backtrace = dlsym (handle, "_Unwind_Backtrace");
|
||||
if (unwind_backtrace != NULL)
|
||||
{
|
||||
unwind_backtrace (backtrace_helper, &arg);
|
||||
assert (arg.cnt != -1 && arg.cnt < 100);
|
||||
}
|
||||
dlclose (handle);
|
||||
}
|
||||
|
||||
/* Since uc_link below has been set to NULL, setcontext is supposed to
|
||||
terminate the process normally after this function returns. */
|
||||
}
|
||||
|
||||
@@ -0,0 +1,230 @@
|
||||
/* Testcase checks, if setcontext(), swapcontext() restores signal-mask
|
||||
and if pending signals are delivered after those calls.
|
||||
Copyright (C) 2015 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for 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 <sys/types.h>
|
||||
#include <signal.h>
|
||||
#include <ucontext.h>
|
||||
#include <unistd.h>
|
||||
|
||||
volatile int global;
|
||||
volatile sig_atomic_t handlerCalled;
|
||||
|
||||
static void
|
||||
check (const char *funcName)
|
||||
{
|
||||
sigset_t set;
|
||||
|
||||
/* check if SIGUSR2 is unblocked after setcontext-call. */
|
||||
sigprocmask (SIG_BLOCK, NULL, &set);
|
||||
|
||||
if (sigismember (&set, SIGUSR2) != 0)
|
||||
{
|
||||
printf ("FAIL: SIGUSR2 is blocked after %s.\n", funcName);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (sigismember (&set, SIGUSR1) != 1)
|
||||
{
|
||||
printf ("FAIL: SIGUSR1 is not blocked after %s.\n", funcName);
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
signalmask (int how, int signum)
|
||||
{
|
||||
sigset_t set;
|
||||
sigemptyset (&set);
|
||||
sigaddset (&set, signum);
|
||||
if (sigprocmask (how, &set, NULL) != 0)
|
||||
{
|
||||
printf ("FAIL: sigprocmaks (%d, %d, NULL): %m\n", how, signum);
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
signalpending (int signum, const char *msg)
|
||||
{
|
||||
sigset_t set;
|
||||
sigemptyset (&set);
|
||||
if (sigpending (&set) != 0)
|
||||
{
|
||||
printf ("FAIL: sigpending: %m\n");
|
||||
exit (1);
|
||||
}
|
||||
if (sigismember (&set, SIGUSR2) != 1)
|
||||
{
|
||||
printf ("FAIL: Signal %d is not pending %s\n", signum, msg);
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
handler (int __attribute__ ((unused)) signum)
|
||||
{
|
||||
handlerCalled ++;
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
ucontext_t ctx, oldctx;
|
||||
struct sigaction action;
|
||||
pid_t pid;
|
||||
|
||||
pid = getpid ();
|
||||
|
||||
/* unblock SIGUSR2 */
|
||||
signalmask (SIG_UNBLOCK, SIGUSR2);
|
||||
|
||||
/* block SIGUSR1 */
|
||||
signalmask (SIG_BLOCK, SIGUSR1);
|
||||
|
||||
/* register handler for SIGUSR2 */
|
||||
action.sa_flags = 0;
|
||||
action.sa_handler = handler;
|
||||
sigemptyset (&action.sa_mask);
|
||||
sigaction (SIGUSR2, &action, NULL);
|
||||
|
||||
if (getcontext (&ctx) != 0)
|
||||
{
|
||||
printf ("FAIL: getcontext: %m\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
global++;
|
||||
|
||||
if (global == 1)
|
||||
{
|
||||
puts ("after getcontext");
|
||||
|
||||
/* block SIGUSR2 */
|
||||
signalmask (SIG_BLOCK, SIGUSR2);
|
||||
|
||||
/* send SIGUSR2 to me */
|
||||
handlerCalled = 0;
|
||||
kill (pid, SIGUSR2);
|
||||
|
||||
/* was SIGUSR2 handler called? */
|
||||
if (handlerCalled != 0)
|
||||
{
|
||||
puts ("FAIL: signal handler was called, but signal was blocked.");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/* is SIGUSR2 pending? */
|
||||
signalpending (SIGUSR2, "before setcontext");
|
||||
|
||||
/* SIGUSR2 will be unblocked by setcontext-call. */
|
||||
if (setcontext (&ctx) != 0)
|
||||
{
|
||||
printf ("FAIL: setcontext: %m\n");
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
else if (global == 2)
|
||||
{
|
||||
puts ("after setcontext");
|
||||
|
||||
/* check SIGUSR1/2 */
|
||||
check ("setcontext");
|
||||
|
||||
/* was SIGUSR2 handler called? */
|
||||
if (handlerCalled != 1)
|
||||
{
|
||||
puts ("FAIL: signal handler was not called after setcontext.");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/* block SIGUSR2 */
|
||||
signalmask (SIG_BLOCK, SIGUSR2);
|
||||
|
||||
/* send SIGUSR2 to me */
|
||||
handlerCalled = 0;
|
||||
kill (pid, SIGUSR2);
|
||||
|
||||
/* was SIGUSR2 handler called? */
|
||||
if (handlerCalled != 0)
|
||||
{
|
||||
puts ("FAIL: signal handler was called, but signal was blocked.");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/* is SIGUSR2 pending? */
|
||||
signalpending (SIGUSR2, "before swapcontext");
|
||||
|
||||
if (swapcontext (&oldctx, &ctx) != 0)
|
||||
{
|
||||
printf ("FAIL: swapcontext: %m\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
puts ("after returned from swapcontext");
|
||||
|
||||
if (global != 3)
|
||||
{
|
||||
puts ("FAIL: returned from swapcontext without ctx-context called.");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
puts ("test succeeded");
|
||||
return 0;
|
||||
}
|
||||
else if ( global != 3 )
|
||||
{
|
||||
puts ("FAIL: 'global' not incremented three times");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
puts ("after swapcontext");
|
||||
/* check SIGUSR1/2 */
|
||||
check ("swapcontext");
|
||||
|
||||
/* was SIGUSR2 handler called? */
|
||||
if (handlerCalled != 1)
|
||||
{
|
||||
puts ("FAIL: signal handler was not called after swapcontext.");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/* check sigmask in old context of swapcontext-call */
|
||||
if (sigismember (&oldctx.uc_sigmask, SIGUSR2) != 1)
|
||||
{
|
||||
puts ("FAIL: SIGUSR2 is not blocked in oldctx.uc_sigmask.");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (sigismember (&oldctx.uc_sigmask, SIGUSR1) != 1)
|
||||
{
|
||||
puts ("FAIL: SIGUSR1 is not blocked in oldctx.uc_sigmaks.");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/* change to old context, which was gathered by swapcontext() call. */
|
||||
setcontext (&oldctx);
|
||||
|
||||
puts ("FAIL: returned from setcontext (&oldctx)");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
#define TEST_FUNCTION do_test ()
|
||||
#include "../test-skeleton.c"
|
||||
@@ -25,6 +25,3 @@ typedef struct
|
||||
|
||||
|
||||
extern void *__tls_get_addr (tls_index *ti);
|
||||
|
||||
/* Value used for dtv entries for which the allocation is delayed. */
|
||||
#define TLS_DTV_UNALLOCATED ((void *) -1l)
|
||||
|
||||
@@ -25,17 +25,7 @@
|
||||
# include <stdbool.h>
|
||||
# include <stddef.h>
|
||||
# include <stdint.h>
|
||||
|
||||
/* Type for the dtv. */
|
||||
typedef union dtv
|
||||
{
|
||||
size_t counter;
|
||||
struct
|
||||
{
|
||||
void *val;
|
||||
bool is_static;
|
||||
} pointer;
|
||||
} dtv_t;
|
||||
# include <dl-dtv.h>
|
||||
|
||||
#else /* __ASSEMBLER__ */
|
||||
# include <tcb-offsets.h>
|
||||
|
||||
@@ -25,6 +25,3 @@ typedef struct
|
||||
} tls_index;
|
||||
|
||||
extern void *__tls_get_addr (tls_index *ti);
|
||||
|
||||
/* Value used for dtv entries for which the allocation is delayed. */
|
||||
#define TLS_DTV_UNALLOCATED ((void *) -1l)
|
||||
|
||||
@@ -25,17 +25,7 @@
|
||||
# include <stdbool.h>
|
||||
# include <stddef.h>
|
||||
# include <stdint.h>
|
||||
|
||||
/* Type for the dtv. */
|
||||
typedef union dtv
|
||||
{
|
||||
size_t counter;
|
||||
struct
|
||||
{
|
||||
void *val;
|
||||
bool is_static;
|
||||
} pointer;
|
||||
} dtv_t;
|
||||
# include <dl-dtv.h>
|
||||
|
||||
/* Get system call information. */
|
||||
# include <sysdep.h>
|
||||
|
||||
@@ -26,6 +26,3 @@ typedef struct dl_tls_index
|
||||
|
||||
|
||||
extern void *__tls_get_addr (tls_index *ti);
|
||||
|
||||
/* Value used for dtv entries for which the allocation is delayed. */
|
||||
#define TLS_DTV_UNALLOCATED ((void *) -1l)
|
||||
|
||||
+1
-11
@@ -25,17 +25,7 @@
|
||||
# include <stdbool.h>
|
||||
# include <stddef.h>
|
||||
# include <stdint.h>
|
||||
|
||||
/* Type for the dtv. */
|
||||
typedef union dtv
|
||||
{
|
||||
size_t counter;
|
||||
struct
|
||||
{
|
||||
void *val;
|
||||
bool is_static;
|
||||
} pointer;
|
||||
} dtv_t;
|
||||
# include <dl-dtv.h>
|
||||
|
||||
#else /* __ASSEMBLER__ */
|
||||
# include <tcb-offsets.h>
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/* Generic declarations for DTV-based TLS handling in the dynamic linker.
|
||||
Copyright (C) 2002-2016 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef _DL_DTV_H
|
||||
#define _DL_DTV_H
|
||||
|
||||
struct dtv_pointer
|
||||
{
|
||||
void *val; /* Pointer to data, or TLS_DTV_UNALLOCATED. */
|
||||
void *to_free; /* Unaligned pointer, for deallocation. */
|
||||
};
|
||||
|
||||
/* Type for the dtv. */
|
||||
typedef union dtv
|
||||
{
|
||||
size_t counter;
|
||||
struct dtv_pointer pointer;
|
||||
} dtv_t;
|
||||
|
||||
/* Value used for dtv entries for which the allocation is delayed. */
|
||||
#define TLS_DTV_UNALLOCATED ((void *) -1l)
|
||||
|
||||
#endif /* _DLT_DTV_H */
|
||||
@@ -38,14 +38,6 @@ typedef int mutex_t;
|
||||
# define mutex_lock(m) ({ *(m) = 1; 0; })
|
||||
# define mutex_trylock(m) (*(m) ? 1 : ((*(m) = 1), 0))
|
||||
# define mutex_unlock(m) (*(m) = 0)
|
||||
# define MUTEX_INITIALIZER (0)
|
||||
|
||||
typedef void *tsd_key_t;
|
||||
# define tsd_key_create(key, destr) do {} while(0)
|
||||
# define tsd_setspecific(key, data) ((key) = (data))
|
||||
# define tsd_getspecific(key, vptr) (vptr = (key))
|
||||
|
||||
# define thread_atfork(prepare, parent, child) do {} while(0)
|
||||
|
||||
#endif /* !defined mutex_init */
|
||||
|
||||
|
||||
@@ -26,6 +26,3 @@ typedef struct
|
||||
|
||||
|
||||
extern void *__tls_get_addr (tls_index *ti);
|
||||
|
||||
/* Value used for dtv entries for which the allocation is delayed. */
|
||||
#define TLS_DTV_UNALLOCATED ((void *) -1l)
|
||||
|
||||
+1
-11
@@ -25,17 +25,7 @@
|
||||
# include <stdbool.h>
|
||||
# include <stddef.h>
|
||||
# include <stdint.h>
|
||||
|
||||
/* Type for the dtv. */
|
||||
typedef union dtv
|
||||
{
|
||||
size_t counter;
|
||||
struct
|
||||
{
|
||||
void *val;
|
||||
bool is_static;
|
||||
} pointer;
|
||||
} dtv_t;
|
||||
# include <dl-dtv.h>
|
||||
|
||||
#else /* __ASSEMBLER__ */
|
||||
# include <tcb-offsets.h>
|
||||
|
||||
@@ -59,6 +59,3 @@ rtld_hidden_def (___tls_get_addr)
|
||||
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Value used for dtv entries for which the allocation is delayed. */
|
||||
#define TLS_DTV_UNALLOCATED ((void *) -1l)
|
||||
|
||||
@@ -36,8 +36,8 @@ ENTRY(__mempcpy_chk)
|
||||
cmpl $0, KIND_OFFSET+__cpu_features@GOTOFF(%ebx)
|
||||
jne 1f
|
||||
call __init_cpu_features
|
||||
leal __mempcpy_chk_ia32@GOTOFF(%ebx), %eax
|
||||
1: testl $bit_SSE2, CPUID_OFFSET+index_SSE2+__cpu_features@GOTOFF(%ebx)
|
||||
1: leal __mempcpy_chk_ia32@GOTOFF(%ebx), %eax
|
||||
testl $bit_SSE2, CPUID_OFFSET+index_SSE2+__cpu_features@GOTOFF(%ebx)
|
||||
jz 2f
|
||||
leal __mempcpy_chk_sse2_unaligned@GOTOFF(%ebx), %eax
|
||||
testl $bit_Fast_Unaligned_Load, FEATURE_OFFSET+index_Fast_Unaligned_Load+__cpu_features@GOTOFF(%ebx)
|
||||
|
||||
+1
-13
@@ -28,19 +28,7 @@
|
||||
# include <sysdep.h>
|
||||
# include <libc-internal.h>
|
||||
# include <kernel-features.h>
|
||||
|
||||
|
||||
/* Type for the dtv. */
|
||||
typedef union dtv
|
||||
{
|
||||
size_t counter;
|
||||
struct
|
||||
{
|
||||
void *val;
|
||||
bool is_static;
|
||||
} pointer;
|
||||
} dtv_t;
|
||||
|
||||
# include <dl-dtv.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
||||
@@ -82,9 +82,7 @@ typedef uintmax_t uatomic_max_t;
|
||||
(__sync_synchronize (), __sync_lock_test_and_set (mem, value))
|
||||
|
||||
#define atomic_exchange_and_add(mem, value) \
|
||||
({ __typeof (*mem) __result; \
|
||||
__result = __sync_fetch_and_add ((mem), (int) (value)); \
|
||||
__result; })
|
||||
__sync_fetch_and_add ((mem), (value))
|
||||
|
||||
#define atomic_decrement_if_positive(mem) \
|
||||
({ __typeof (*mem) __oldval, __val; \
|
||||
|
||||
@@ -28,6 +28,3 @@
|
||||
#define DONT_USE_TLS_INDEX 1
|
||||
|
||||
extern void *__tls_get_addr (size_t m, size_t offset);
|
||||
|
||||
/* Value used for dtv entries for which the allocation is delayed. */
|
||||
#define TLS_DTV_UNALLOCATED ((void *) -1l)
|
||||
|
||||
+1
-13
@@ -26,19 +26,7 @@
|
||||
# include <stdint.h>
|
||||
# include <stdlib.h>
|
||||
# include <list.h>
|
||||
|
||||
|
||||
/* Type for the dtv. */
|
||||
typedef union dtv
|
||||
{
|
||||
size_t counter;
|
||||
struct
|
||||
{
|
||||
void *val;
|
||||
bool is_static;
|
||||
} pointer;
|
||||
} dtv_t;
|
||||
|
||||
# include <dl-dtv.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
||||
@@ -45,6 +45,3 @@ extern void *__tls_get_addr (tls_index *ti);
|
||||
|
||||
#define GET_ADDR_OFFSET (ti->ti_offset + TLS_DTV_OFFSET)
|
||||
#define __TLS_GET_ADDR(__ti) (__tls_get_addr (__ti) - TLS_DTV_OFFSET)
|
||||
|
||||
/* Value used for dtv entries for which the allocation is delayed. */
|
||||
#define TLS_DTV_UNALLOCATED ((void *) -1l)
|
||||
|
||||
+1
-11
@@ -26,17 +26,7 @@
|
||||
# include <stdbool.h>
|
||||
# include <stddef.h>
|
||||
# include <stdint.h>
|
||||
|
||||
/* Type for the dtv. */
|
||||
typedef union dtv
|
||||
{
|
||||
size_t counter;
|
||||
struct
|
||||
{
|
||||
void *val;
|
||||
bool is_static;
|
||||
} pointer;
|
||||
} dtv_t;
|
||||
# include <dl-dtv.h>
|
||||
|
||||
#else /* __ASSEMBLER__ */
|
||||
# include <tcb-offsets.h>
|
||||
|
||||
@@ -50,8 +50,9 @@ typedef struct __libc_lock_recursive_opaque__ __libc_lock_recursive_t;
|
||||
CLASS __libc_lock_t NAME;
|
||||
|
||||
/* Define an initialized lock variable NAME with storage class CLASS. */
|
||||
#define _LIBC_LOCK_INITIALIZER MUTEX_INITIALIZER
|
||||
#define __libc_lock_define_initialized(CLASS,NAME) \
|
||||
CLASS __libc_lock_t NAME = MUTEX_INITIALIZER;
|
||||
CLASS __libc_lock_t NAME = _LIBC_LOCK_INITIALIZER;
|
||||
|
||||
/* Initialize the named lock variable, leaving it in a consistent, unlocked
|
||||
state. */
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <assert.h>
|
||||
#include "hurdmalloc.h" /* XXX */
|
||||
#include <tls.h>
|
||||
#include <malloc/malloc-internal.h>
|
||||
|
||||
#undef __fork
|
||||
|
||||
@@ -107,6 +108,12 @@ __fork (void)
|
||||
/* Run things that prepare for forking before we create the task. */
|
||||
RUN_HOOK (_hurd_fork_prepare_hook, ());
|
||||
|
||||
/* Acquire malloc locks. This needs to come last because fork
|
||||
handlers may use malloc, and the libio list lock has an
|
||||
indirect malloc dependency as well (via the getdelim
|
||||
function). */
|
||||
call_function_static_weak (__malloc_fork_lock_parent);
|
||||
|
||||
/* Lock things that want to be locked before we fork. */
|
||||
{
|
||||
void *const *p;
|
||||
@@ -608,6 +615,9 @@ __fork (void)
|
||||
nthreads * sizeof (*threads));
|
||||
}
|
||||
|
||||
/* Release malloc locks. */
|
||||
call_function_static_weak (__malloc_fork_unlock_parent);
|
||||
|
||||
/* Run things that want to run in the parent to restore it to
|
||||
normality. Usually prepare hooks and parent hooks are
|
||||
symmetrical: the prepare hook arrests state in some way for the
|
||||
@@ -659,6 +669,9 @@ __fork (void)
|
||||
/* Forking clears the trace flag. */
|
||||
__sigemptyset (&_hurdsig_traced);
|
||||
|
||||
/* Release malloc locks. */
|
||||
call_function_static_weak (__malloc_fork_unlock_child);
|
||||
|
||||
/* Run things that want to run in the child task to set up. */
|
||||
RUN_HOOK (_hurd_fork_child_hook, ());
|
||||
|
||||
|
||||
@@ -25,17 +25,7 @@
|
||||
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
/* Type for the dtv. */
|
||||
typedef union dtv
|
||||
{
|
||||
size_t counter;
|
||||
struct
|
||||
{
|
||||
void *val;
|
||||
bool is_static;
|
||||
} pointer;
|
||||
} dtv_t;
|
||||
|
||||
# include <dl-dtv.h>
|
||||
|
||||
/* Type of the TCB. */
|
||||
typedef struct
|
||||
|
||||
@@ -52,16 +52,6 @@
|
||||
/* No we're *not* using pthreads. */
|
||||
#define __pthread_initialize ((void (*)(void))0)
|
||||
|
||||
/* thread specific data for glibc */
|
||||
|
||||
#include <bits/libc-tsd.h>
|
||||
|
||||
typedef int tsd_key_t[1]; /* no key data structure, libc magic does it */
|
||||
__libc_tsd_define (static, void *, MALLOC) /* declaration/common definition */
|
||||
#define tsd_key_create(key, destr) ((void) (key))
|
||||
#define tsd_setspecific(key, data) __libc_tsd_set (void *, MALLOC, (data))
|
||||
#define tsd_getspecific(key, vptr) ((vptr) = __libc_tsd_get (void *, MALLOC))
|
||||
|
||||
/* madvise is a stub on Hurd, so don't bother calling it. */
|
||||
|
||||
#include <sys/mman.h>
|
||||
|
||||
@@ -24,6 +24,3 @@ typedef struct
|
||||
} tls_index;
|
||||
|
||||
extern void *__tls_get_addr (tls_index *ti);
|
||||
|
||||
/* Value used for dtv entries for which the allocation is delayed. */
|
||||
#define TLS_DTV_UNALLOCATED ((void *) -1l)
|
||||
|
||||
@@ -25,17 +25,7 @@
|
||||
# include <stdbool.h>
|
||||
# include <stddef.h>
|
||||
# include <stdint.h>
|
||||
|
||||
/* Type for the dtv. */
|
||||
typedef union dtv
|
||||
{
|
||||
size_t counter;
|
||||
struct
|
||||
{
|
||||
void *val;
|
||||
bool is_static;
|
||||
} pointer;
|
||||
} dtv_t;
|
||||
# include <dl-dtv.h>
|
||||
|
||||
#else /* __ASSEMBLER__ */
|
||||
# include <tcb-offsets.h>
|
||||
|
||||
@@ -43,6 +43,3 @@ extern void *__tls_get_addr (tls_index *ti);
|
||||
|
||||
# define GET_ADDR_OFFSET (ti->ti_offset + TLS_DTV_OFFSET)
|
||||
# define __TLS_GET_ADDR(__ti) (__tls_get_addr (__ti) - TLS_DTV_OFFSET)
|
||||
|
||||
/* Value used for dtv entries for which the allocation is delayed. */
|
||||
#define TLS_DTV_UNALLOCATED ((void *) -1l)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user