Compare commits

...
Author SHA1 Message Date
Joseph Myers a67ffcfae3 Make io/ftwtest-sh remove temporary files on early exit.
The test io/ftwtest-sh creates a directory that at some points during
the test does not have execute permission.  To avoid leaving behind
such a directory that prevents the build directory from being removed
with a simple "rm -rf", it traps various signals to make the directory
executable and remove it before exit.  However, this doesn't cover the
case where one of the tests simply fails (which happens with cross
testing if testing on a remote system where the path to the build
directory involves a symlink, or if that remote system fell over
during testing - I think the latter is the case where the directory is
left behind with bad permissions).

This patch makes that test also trap signal 0 (exit) so that the
directory gets properly removed in such failure cases as well.

Tested in both configurations where the test passes and where it fails
to verify that the result of the test is unchanged but the directory
is no longer left behind where it was previously left behind.

	* io/ftwtest-sh: Also trap on exit to remove temporary files.
2017-04-21 10:07:56 -03:00
Adhemerval Zanella 136c42bf12 posix: Add cleanup on the trap list for globtest.sh
This patch prevents lingering files for SIGSEGV failures by adding
a cleanup handler on trap handler.  Checked on x86_64-linux-gnu.

	* posix/globtest.sh: Add cleanup routine on trap 0.

Cherry-pick of 4fee33f.
2017-04-20 14:58:25 -03:00
Adhemerval Zanella 43765a182c malloc: Fix i686 build from malloc interpose backport
This patch fixes i686 build after malloc interpose fix backport
(commit 749c94d4).

Checked on i686-linux-gnu.

	* malloc/arena.c (__malloc_fork_lock_parent): Add internal_function
	attribute.
	(__malloc_fork_unlock_parent): Likewise.
	(__malloc_fork_unlock_child): Likewise.
2017-02-07 12:10:25 -02:00
H.J. Lu 1b248392fb Extend local PLT reference check
On x86, linker in binutils 2.26 and newer consolidates R_*_JUMP_SLOT with
R_*_GLOB_DAT relocation against the same symbol.  This patch extends
local PLT reference check to support alternate relocations.

	[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.
2017-01-27 13:16:53 -02:00
Alan Modra cf161d3911 Fix localplt test breakage with new readelf
Since 2014-11-24 binutils git commit bb4d2ac2, readelf has appended
the symbol version to symbols shown in reloc dumps.

	[BZ #16512]
	* scripts/localplt.awk: Strip off symbol version.
	* NEWS: Mention bug fix.
2017-01-27 13:16:52 -02:00
Florian Weimer a274119b0e malloc: Simplify static malloc interposition [BZ #20432]
Existing interposed mallocs do not define the glibc-internal
fork callbacks (and they should not), so statically interposed
mallocs lead to link failures because the strong reference from
fork pulls in glibc's malloc, resulting in multiple definitions
of malloc-related symbols.
2017-01-27 13:16:52 -02:00
Florian Weimer a18c25e0ee nptl/tst-tls3-malloc: Force freeing of thread stacks
It turns out that due to the reduced stack size in tst-tls3 and the
(fixed) default stack cache size, allocated TLS variables are never
freed, so the test coverage for tst-tls3-malloc is less than complete.
This change increases the thread stack size for tst-tls3-malloc only,
to make sure thread stacks and TLS variables are freed.
2017-01-27 13:16:52 -02:00
Florian Weimer 124ea50584 malloc: Run tests without calling mallopt [BZ #19469]
The compiled tests no longer refer to the mallopt symbol
from their main functions.  (Some tests still call mallopt
explicitly, which is fine.)
2017-01-27 13:16:52 -02:00
Florian Weimer 5a8692a646 elf: Do not use memalign for TCB/TLS blocks allocation [BZ #17730]
Instead, call malloc and explicitly align the pointer.

There is no external location to store the original (unaligned)
pointer, and this commit increases the allocation size to store
the pointer at a fixed location relative to the TCB pointer.

The manual alignment means that some space goes unused which
was previously made available for subsequent allocations.
However, in the TLS_DTV_AT_TP case, the manual alignment code
avoids aligning the pre-TCB to the TLS block alignment.  (Even
while using memalign, the allocation had some unused padding
in front.)

This concludes the removal of memalign calls from the TLS code,
and the new tst-tls3-malloc test verifies that only core malloc
routines are used.
2017-01-27 13:16:29 -02:00
Florian Weimer 6a277a415c elf: Avoid using memalign for TLS allocations [BZ #17730]
Instead of a flag which indicates the pointer can be freed, dtv_t
now includes the pointer which should be freed.  Due to padding,
the size of dtv_t does not increase.

To avoid using memalign, the new allocate_dtv_entry function
allocates a sufficiently large buffer so that a sub-buffer
can be found in it which starts with an aligned pointer.  Both
the aligned and original pointers are kept, the latter for calling
free later.
2017-01-27 13:16:28 -02:00
Alexandre Oliva 9e1e8f68d5 Fix DTV race, assert, DTV_SURPLUS Static TLS limit, and nptl_db garbage
for  ChangeLog

	[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.
2017-01-27 13:16:28 -02:00
Florian Weimer dd08634b37 elf: Consolidate machine-agnostic DTV definitions in <dl-dtv.h>
Identical definitions of dtv_t and TLS_DTV_UNALLOCATED were
repeated for all architectures using DTVs.
2017-01-27 13:16:28 -02:00
Florian Weimer 749c94d44c malloc: Run fork handler as late as possible [BZ #19431]
Previously, a thread M invoking fork would acquire locks in this order:

  (M1) malloc arena locks (in the registered fork handler)
  (M2) libio list lock

A thread F invoking flush (NULL) would acquire locks in this order:

  (F1) libio list lock
  (F2) individual _IO_FILE locks

A thread G running getdelim would use this order:

  (G1) _IO_FILE lock
  (G2) malloc arena lock

After executing (M1), (F1), (G1), none of the threads can make progress.

This commit changes the fork lock order to:

  (M'1) libio list lock
  (M'2) malloc arena locks

It explicitly encodes the lock order in the implementations of fork,
and does not rely on the registration order, thus avoiding the deadlock.
2017-01-27 13:16:28 -02:00
Florian Weimer b533edfeed malloc: Fix list_lock/arena lock deadlock [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.
2017-01-27 13:16:28 -02:00
Florian Weimer 4b31bd831a 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.
2017-01-27 13:16:28 -02:00
Florian Weimer 50992336ac malloc: Prevent arena free_list from turning cyclic [BZ #19048]
[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.
2017-01-27 13:16:27 -02:00
Florian Weimer 39ad1d1244 malloc: Rewrite with explicit TLS access using __thread 2017-01-27 13:16:27 -02:00
Siddhesh Poyarekar 7f2efd6c26 Consolidate arena_lookup and arena_lock into a single arena_get
This seems to have been left behind as an artifact of some old changes
and can now be merged.  Verified that the only generated code change
on x86_64 is that of line numbers in asserts, like so:

@@ -27253,7 +27253,7 @@ Disassembly of section .text:
   416f09:      48 89 42 20             mov    %rax,0x20(%rdx)
   416f0d:      e9 7e f6 ff ff          jmpq   416590 <_int_free+0x230>
   416f12:      b9 3f 9f 4a 00          mov    $0x4a9f3f,%ecx
-  416f17:      ba d5 0f 00 00          mov    $0xfd5,%edx
+  416f17:      ba d6 0f 00 00          mov    $0xfd6,%edx
   416f1c:      be a8 9b 4a 00          mov    $0x4a9ba8,%esi
   416f21:      bf 6a 9c 4a 00          mov    $0x4a9c6a,%edi
   416f26:      e8 45 e8 ff ff          callq  415770 <__malloc_assert>
2017-01-27 13:15:58 -02:00
Adhemerval Zanella a68cafa11c Add runtime check for __ASSUME_REQUEUE_PI (BZ# 18463)
This patch adds a runtime check for requeue priority futexes
(FUTEX_{WAIT,CMP}_REQUEUE_PI) for configurations that do not define
__ASSUME_REQUEUE_PI.

It uses the same check uses for priority lock/unlock support, where
issuing a futex operation with FUTEX_UNLOCK_PI returns if kernel has
or not internal 'futex_cmpxchg_enabled' support (which is also used
on requeue priority futexes operations).

For architectures that already have __ASSUME_REQUEUE_PI the code
flow does not change, 'use_requeue_pi' returns the previous chec
logic.  Also, if 'futex_cmpxchg_enabled' is not supported by the
kernel, the previous logic will be used (by issuing a default futex
operation).

Tested on ARM (v3.8 kernel) and x86_64.

	* 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.
2016-06-07 10:38:17 -03:00
Adhemerval Zanella 6e5cb616b5 Remove __ASSUME_SET_ROBUST_LIST
This patch removes __ASSUME_SET_ROBUST_LIST usage and assumes that
kernel will correctly return if it supports or not
futex_atomic_cmpxchg_inatomic.

On minimum supported kernel (v3.2 and v2.6.32 for x86) kernel has:

2418 SYSCALL_DEFINE2(set_robust_list, struct robust_list_head __user *, head,
2419                 size_t, len)
2420 {
2421         if (!futex_cmpxchg_enabled)
2422                 return -ENOSYS;

The patch also adds the __set_robust_list_avail runtime check for all
architectures, since for some the syscall may still return ENOSYS if
futex_atomic_cmpxchg_inatomic is not supported (for instance ARM).

Tested on armhf (with 3.8 kernel) and x86_64.

	* 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.
2016-06-07 10:38:17 -03:00
Roland McGrath 02b2a80526 Fix nptl-init.c use of INTERNAL_SYSCALL_DECL. 2016-06-07 10:38:01 -03:00
Adhemerval Zanella 9ac61c0047 Remove __ASSUME_FUTEX_LOCK_PI
This patch removes __ASSUME_FUTEX_LOCK_PI usage and assumes that
kernel will correctly return if it supports or not
futex_atomic_cmpxchg_inatomic.

Current PI mutex code already has runtime support by calling
prio_inherit_missing and returns ENOTSUP if the futex operation fails
at initialization (it issues a FUTEX_UNLOCK_PI futex operation).

Also, current minimum supported kernel (v3.2) will return ENOSYS if
futex_atomic_cmpxchg_inatomic is not supported in the system:

kernel/futex.c:

2628 long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
2629                 u32 __user *uaddr2, u32 val2, u32 val3)
2630 {
2631         int ret = -ENOSYS, cmd = op & FUTEX_CMD_MASK;
[...]
2667         case FUTEX_UNLOCK_PI:
2668                 if (futex_cmpxchg_enabled)
2669                         ret = futex_unlock_pi(uaddr, flags);
[...]
2686         return ret;
2687 }

The futex_cmpxchg_enabled is initialized by calling cmpxchg_futex_value_locked,
which calls futex_atomic_cmpxchg_inatomic.

For ARM futex_atomic_cmpxchg_inatomic will be either defined (if both
CONFIG_CPU_USE_DOMAINS and CONFIG_SMP are not defined) or use the
default generic implementation that returns ENOSYS.

For m68k is uses the default generic implementation.

For mips futex_atomic_cmpxchg_inatomic will return ENOSYS if cpu has no
'cpu_has_llsc' support (defined by each chip supporte inside kernel).

For sparc, 32-bit kernel will just use default generic implementation,
while 64-bit kernel has support.

Tested on ARM (v3.8 kernel) and x86_64.

	* 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-06-07 10:33:38 -03:00
Yvan Roux 59c0f6ff86 Suppress GCC 6 warning about ambiguous 'else' with -Wparentheses
Backport of df1cf48777.

	* stdlib/setenv.c (unsetenv): Fix ambiguous 'else'.
	* nis/nis_call.c (nis_server_cache_add): Likewise.
2016-05-09 10:03:50 -03:00
Stefan Liebler 94dc51ad84 S390: Fix "backtrace() returns infinitely deep stack frames with makecontext()" [BZ #18508].
On s390/s390x backtrace(buffer, size) returns the series of called functions until
"makecontext_ret" and additional entries (up to "size") with "makecontext_ret".
GDB-backtrace is also warning:
"Backtrace stopped: previous frame identical to this frame (corrupt stack?)"

To reproduce this scenario you have to setup a new context with makecontext()
and activate it with setcontext(). See e.g. cf() function in testcase stdlib/tst-makecontext.c.
Or see bug in libgo "Bug 66303 - runtime.Caller() returns infinitely deep stack frames
on s390x " (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66303).

This patch omits the cfi_startproc/cfi_endproc directives in ENTRY/END macro of
__makecontext_ret. Thus no frame information is generated in .eh_frame and backtrace
stops after __makecontext_ret. There is also no .eh_frame info for _start or
thread_start functions.

ChangeLog:

	[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.

(cherry picked from commit 890b7a4b33)
2016-04-28 10:30:09 +02:00
Stefan Liebler 50d2d4bb0e S/390: Fix setcontext/swapcontext which are not restoring sigmask.
This patch uses sigprocmask(SIG_SETMASK) instead of SIG_BLOCK
in setcontext, swapcontext.

(cherry picked from commit 2e807f2959)
2016-04-28 10:29:07 +02:00
Mike Frysinger 3a6219d3ec configure: fix test == usage
POSIX defines the = operator, but not ==.  Fix the few places where we
incorrectly used ==.

(cherry picked from commit b2d4456b33)
2016-04-09 20:10:33 -04:00
Stefan Liebler f5eb5f9c91 S390: Extend structs La_s390_regs / La_s390_retval with vector-registers.
Starting with z13, vector registers can also occur as argument registers.
Thus the passed input/output register structs for
la_s390_[32|64]_gnu_plt[enter|exit] functions should reflect those new
registers. This patch extends these structs La_s390_regs and La_s390_retval
and adjusts _dl_runtime_profile() to handle those fields in case of
running on a z13 machine.

ChangeLog:

	* 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.

(cherry picked from commit 5cdd1989d1)
2016-04-04 13:19:57 +02:00
Stefan Liebler 3b7f56026c S390: Save and restore fprs/vrs while resolving symbols.
On s390, no fpr/vrs were saved while resolving a symbol
via _dl_runtime_resolve/_dl_runtime_profile.

According to the abi, the fpr-arguments are defined as call clobbered.
In leaf-functions, gcc 4.9 and newer can use fprs for saving/restoring gprs
instead of saving them to the stack.
If gcc do this in one of the resolver-functions, then the floating point
arguments of a library-function are invalid for the first library-function-call.
Thus, this patch saves/restores the fprs around the resolving code.

The same could occur for vector registers. Furthermore an ifunc-resolver
could also clobber the vector/floating point argument registers.
Thus this patch provides the further variants _dl_runtime_resolve_vx/
_dl_runtime_profile_vx, which are used if the kernel claims, that
we run on a machine with vector registers.

Furthermore, if _dl_runtime_profile calls _dl_call_pltexit,
the pointers to inregs-/outregs-structs were setup invalid.
Now they point to the correct location in the stack-frame.
Before branching back to the caller, the return values are now
restored instead of containing the return values of the
_dl_call_pltexit() call.
On s390-32, an endless loop occurs if _dl_call_pltexit() should be called.
Now, this code-path branches to this function instead of just after the
preceding basr-instruction.

ChangeLog:

	* 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.

(cherry picked from commit 4603c51ef7
and commit d8a012c5c9)
2016-04-04 13:19:57 +02:00
Stefan Liebler daf161ce63 S390: configure check for vector instruction support in assembler.
The S390 specific test checks if the assembler has support for the new z13
vector instructions by compiling a vector instruction. The .machine and
.machinemode directives are needed to compile the vector instruction without
-march=z13 option on 31/64 bit.
On success the macro HAVE_S390_VX_ASM_SUPPORT is defined. This macro is used
to determine if the optimized functions can be build without compile errors.
If the used assembler lacks vector support, then a warning is dumped while
configuring and only the common code functions are build.

The z13 instruction support was introduced in
"[Committed] S/390: Add support for IBM z13."
(https://sourceware.org/ml/binutils/2015-01/msg00197.html)

ChangeLog:

	* 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.

(cherry picked from commit 4f0a1cea34)
2016-04-04 13:19:57 +02:00
Stefan Liebler 87efefb037 S390: Add new s390 platform.
The new IBM z13 is added to platform string array.
The macro _DL_PLATFORMS_COUNT is incremented to 8,
because it was not incremented by commit
"S/390: Sync AUXV capabilities and archs with kernel".

ChangeLog:

	* sysdeps/s390/dl-procinfo.c (_dl_s390_cap_flags): Add z13.
	* sysdeps/s390/dl-procinfo.h (_DL_PLATFORMS_COUNT): Increased.

(cherry picked from commit a1b0488fc9)
2016-04-04 13:19:57 +02:00
Stefan Liebler 65c7020d26 S390: Add hwcaps value for vector facility.
The HWCAP_S390_VX flag in hwcap field of auxiliary vector indicates
if the vector facility is available and the kernel is aware of it.
This can be tested with LD_SHOW_AUXV=1 <prog>.
Currently it does not show te, because it was not incremented
by commit "S/390: Add hwcap value for transactional execution.".
Thus _DL_HWCAP_COUNT is incremented by two.

ChangeLog:

	* 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.

(cherry picked from commit 4e28fa8088)
2016-04-04 13:19:57 +02:00
Hongjiu Zhang 9f95ec0adb sln: use stat64
When using sln on some filesystems which return 64-bit inodes,
the stat call might fail during install like so:
	.../elf/sln .../elf/symlink.list
	/lib32/libc.so.6: invalid destination: Value too large for defined data type
	/lib32/ld-linux.so.2: invalid destination: Value too large for defined data type
	Makefile:104: recipe for target 'install-symbolic-link' failed

Switch to using stat64 all the time to avoid this.

URL: https://bugs.gentoo.org/576396
(cherry picked from commit f5e753c8c3)
2016-03-07 11:45:43 -05:00
Stefan Liebler 1885fe873e S390: Do not use direct socket syscalls if build on kernels >= 4.3. [BZ #19682]
Beginning with Linux 4.3, the kernel headers contain direct
system call numbers __NR_socket etc. on s390x. On older kernels,
the socket-multiplexer syscall __NR_socketcall was used.

To enable these new syscalls, the patch
"S390: Call direct system calls for socket operations."
(https://sourceware.org/git/?p=glibc.git;a=commit;h=016495b818cb61df7d0d10e6db54074271b3e3a5)
was applied upstream.

If glibc 2.23 is configured with --enable-kernel=4.3 and newer,
the direct socket syscalls are used.
For older kernels, the socket-multiplexer syscall is used instead.

In glibc 2.22 and earlier, this patch is not applied.
If you build glibc on a kernel < 4.3, the socket-multiplexer
syscall is used. But if you build glibc on kernel >= 4.3, the
direct socket-syscalls are used. If you install this glibc on a
kernel < 4.3, all socket operations will fail.
See "Bug 19682 - s390x: Incorrect syscall definitions cause
breakage with Linux 4.3 headers"
(https://sourceware.org/bugzilla/show_bug.cgi?id=19682)
The configure switch --enable-kernel does not influence this
behaviour on older glibc-releases.

The solution is to remove the direct socket-syscalls in
sysdeps/unix/sysv/linux/s390/s390-64/syscalls.list
(this patch) on older glibc-releases as it was done by the
upstream patch, too. These entries were never used on s390x,
but the c-files in sysdeps/unix/sysv/linux/.
After this removal, the behaviour of the socket functions are
not changed compared to the original glibc release version
and the socket-multiplexer-syscall is always used.
2016-03-03 08:22:43 +01:00
Carlos O'Donell 16d0a0ce76 CVE-2015-7547: getaddrinfo() stack-based buffer overflow (Bug 18665).
* 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)

See also:
https://sourceware.org/ml/libc-alpha/2016-02/msg00416.html
https://sourceware.org/ml/libc-alpha/2016-02/msg00418.html

(cherry picked from commit e9db92d3ac)
2016-02-16 22:28:58 -05:00
Florian Weimer 014eaa2207 hsearch_r: Apply VM size limit in test case
(cherry picked from commit f34f146e68)
2016-02-16 21:52:07 +01:00
Florian Weimer 965630aefa Improve check against integer wraparound in hcreate_r [BZ #18240]
(cherry picked from commit bae7c7c764)
2016-01-29 18:01:51 +01:00
Ondřej Bílka 51e762570e Handle overflow in __hcreate_r
Hi,

As in bugzilla entry there is overflow in hsearch when looking for prime
number as SIZE_MAX - 1 is divisible by 5. We fix that by rejecting large
inputs before looking for prime.

	* misc/hsearch_r.c (__hcreate_r): Handle overflow.

(cherry picked from commit 2f5c175055)
2016-01-29 17:57:31 +01:00
Paul Pluzhnikov 163437ec37 Fix BZ #18985 -- out of range data to strftime() causes a segfault
(cherry picked from commit d36c75fc0d)
2016-01-23 18:16:50 +01:00
Paul Pluzhnikov f676ce661c Fix trailing space.
(cherry picked from commit 7565d2a862)
2016-01-23 18:14:45 +01:00
Paul Pluzhnikov 907cc11c57 Fix BZ #17905
(cherry picked from commit 0f58539030)
2016-01-23 18:14:15 +01:00
Szabolcs Nagy dbcaca73cb [AArch64] Fix the big endian loader name.
(cherry picked from commit 44cb254f9a)
2015-12-01 13:37:51 -02:00
Mike Frysinger 26f36461f6 nscd: drop selinux/flask.h include
Building nscd w/selinux enabled yields a warning which yields an error:
In file included from selinux.c:32:0:
/usr/include/selinux/flask.h:5:2: error:
 #warning "Please remove any #include's of this header in your source code."

I've done just that and it builds cleanly with libselinux-2.4.

(cherry picked from commit 8086966968)
2015-11-22 19:31:14 +01:00
Andreas Schwab e04da210f7 Fix parallel build error
(cherry picked from commit e8b6be0016)
2015-10-28 14:29:27 +00:00
Florian Weimer e871e19b5f CVE-2014-8121: Do not close NSS files database during iteration [BZ #18007]
Robin Hack discovered Samba would enter an infinite loop processing
certain quota-related requests.  We eventually tracked this down to a
glibc issue.

Running a (simplified) test case under strace shows that /etc/passwd
is continuously opened and closed:

…
open("/etc/passwd", O_RDONLY|O_CLOEXEC) = 3
lseek(3, 0, SEEK_CUR)                   = 0
read(3, "root:x:0:0:root:/root:/bin/bash\n"..., 4096) = 2717
lseek(3, 2717, SEEK_SET)                = 2717
close(3)                                = 0
open("/etc/passwd", O_RDONLY|O_CLOEXEC) = 3
lseek(3, 0, SEEK_CUR)                   = 0
lseek(3, 0, SEEK_SET)                   = 0
read(3, "root:x:0:0:root:/root:/bin/bash\n"..., 4096) = 2717
lseek(3, 2717, SEEK_SET)                = 2717
close(3)                                = 0
open("/etc/passwd", O_RDONLY|O_CLOEXEC) = 3
lseek(3, 0, SEEK_CUR)                   = 0
…

The lookup function implementation in
nss/nss_files/files-XXX.c:DB_LOOKUP has code to prevent that.  It is
supposed skip closing the input file if it was already open.

  /* Reset file pointer to beginning or open file.  */			      \
  status = internal_setent (keep_stream);				      \
									      \
  if (status == NSS_STATUS_SUCCESS)					      \
    {									      \
      /* Tell getent function that we have repositioned the file pointer.  */ \
      last_use = getby;							      \
									      \
      while ((status = internal_getent (result, buffer, buflen, errnop	      \
					H_ERRNO_ARG EXTRA_ARGS_VALUE))	      \
	     == NSS_STATUS_SUCCESS)					      \
	{ break_if_match }						      \
									      \
      if (! keep_stream)						      \
	internal_endent ();						      \
    }									      \

keep_stream is initialized from the stayopen flag in internal_setent.
internal_setent is called from the set*ent implementation as:

  status = internal_setent (stayopen);

However, for non-host database, this flag is always 0, per the
STAYOPEN magic in nss/getXXent_r.c.

Thus, the fix is this:

-  status = internal_setent (stayopen);
+  status = internal_setent (1);

This is not a behavioral change even for the hosts database (where the
application can specify the stayopen flag) because with a call to
sethostent(0), the file handle is still not closed in the
implementation of gethostent.

(cherry picked from commit 03d2730b44)

Conflicts:
	ChangeLog
	NEWS
2015-10-19 11:02:27 +02:00
Mike Frysinger f2cdbadd8a getmntent: fix memory corruption w/blank lines [BZ #18887]
The fix for BZ #17273 introduced a single byte of memory corruption when
the line is entirely blank.  It would walk back past the start of the
buffer if the heap happened to be 0x20 or 0x09 and then write a NUL byte.
	buffer = '\n';
	end_ptr = buffer;
	while (end_ptr[-1] == ' ' || end_ptr[-1] == '\t')
		end_ptr--;
	*end_ptr = '\0';

Fix that and rework the tests.  Adding the testcase for BZ #17273 to the
existing \040 parser does not really make sense as it's unrelated, and
leads to confusing behavior: it implicitly relies on the new entry being
longer than the previous entry (since it just rewinds the FILE*).  Split
it out into its own dedicated testcase instead.

(cherry picked from commit b0e805fa0d)
2015-08-29 18:12:23 -04:00
Mike Frysinger 978908245b ia64: atomic.h: fix atomic_exchange_and_add 64bit handling
Way back in 2005 the atomic_exchange_and_add function was cleaned up to
avoid the explicit size checking and instead let gcc handle things itself.
Unfortunately that change ended up leaving beyond a cast to int, even when
the incoming value was a long.  This has flown under the radar for a long
time due to the function not being heavily used in the tree (especially as
a full 64bit field), but a recent change to semaphores made some nptl tests
fail reliably.  This is due to the code packing two 32bit values into one
64bit variable (where the high 32bits contained the number of waiters), and
then the whole variable being atomically updated between threads.  On ia64,
that meant we never atomically updated the count, so sometimes the sem_post
would not wake up the waiters.

(cherry picked from commit cf31a2c799)
2015-07-28 05:03:27 -04:00
Paul Pluzhnikov 8a4e5cc657 Fix BZ #17269 -- _IO_wstr_overflow integer overflow
(cherry picked from commit bdf1ff052a)
2015-07-20 22:35:37 -04:00
Andreas Schwab fe7b1136e5 Fix read past end of pattern in fnmatch (bug 18032)
(cherry picked from commit 4a28f4d55a)
2015-07-20 22:19:12 -04:00
Mike Frysinger d679497db2 sparc: fix sigaction for 32bit builds [BZ #18694]
Commit a059d359d8 changed the sigaction
struct to pass conform tests, but it ended up also changing the ABI for
32 bit builds.  For 64 bit builds, changing the long to two ints works,
but for 32 bit builds, it inserts 4 extra bytes.  This leads to many
packages randomly failing like bash that spews things like:
	configure: line 471: wait_for: No record of process 0

Bracket the new member by a wordsize check to fix the ABI for 32bit.

(cherry picked from commit 7fde904c73)
2015-07-20 21:59:58 -04:00
Arjun Shankar 01b07c70ad CVE-2015-1781: resolv/nss_dns/dns-host.c buffer overflow [BZ#18287]
(cherry picked from commit 2959eda927)
2015-04-22 20:01:12 +10:00
Evangelos Foutras 75adf430d2 Fix __memcpy_chk on non-SSE2 CPUs
In commit 8b4416d, the 1: jump label in __mempcpy_chk was accidentally
moved.  This resulted in failures of mempcpy on CPU without SSE2.

(cherry picked from commit 132a1328ec)
2015-02-10 21:43:02 +10:00
Florian Weimer c66e8b9e58 NEWS: Also mention CVE-2015-1473 2015-02-06 16:30:15 +01:00
Carlos O'Donell 004c993bdd Fix missing ChangeLog attribution. 2015-02-06 02:00:52 -05:00
150 changed files with 4153 additions and 1064 deletions
+598
View File
@@ -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.
+42 -4
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
+31
View File
@@ -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;
}
+6
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
-6
View File
@@ -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
View File
@@ -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;
}
+2 -2
View File
@@ -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
View File
@@ -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;
+15
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+32
View File
@@ -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
View File
@@ -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;
+20
View File
@@ -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"
+20
View File
@@ -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"
+270
View File
@@ -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;
}
}
+30
View File
@@ -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 */
+20
View File
@@ -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"
+210
View File
@@ -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;
}
+19
View File
@@ -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"
+19
View File
@@ -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"
+20
View File
@@ -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"
+220
View File
@@ -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;
}
-12
View File
@@ -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
View File
@@ -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
+97
View File
@@ -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
View File
@@ -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
View File
@@ -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';
}
+45
View File
@@ -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"
+53
View File
@@ -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"
-20
View File
@@ -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
View File
@@ -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
View File
@@ -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
+4 -9
View File
@@ -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
View File
@@ -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
View File
@@ -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
+2 -3
View File
@@ -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,
+2 -3
View File
@@ -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,
+4 -7
View File
@@ -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);
+5 -8
View File
@@ -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);
+1 -7
View File
@@ -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. */
+4 -8
View File
@@ -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;
}
+31
View File
@@ -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
View File
@@ -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
View File
@@ -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"
+4
View File
@@ -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;
+2 -1
View File
@@ -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;
+39
View File
@@ -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
+3 -4
View File
@@ -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
View File
@@ -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;
+6 -5
View File
@@ -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. */
-1
View File
@@ -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
View File
@@ -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.
+1 -1
View File
@@ -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)
{
+118
View File
@@ -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"
+2 -3
View File
@@ -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
View File
@@ -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
+5 -3
View File
@@ -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
View File
@@ -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;
+3
View File
@@ -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
View File
@@ -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);
+35 -5
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+40 -1
View File
@@ -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. */
}
+230
View File
@@ -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"
-3
View File
@@ -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)
+1 -11
View File
@@ -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>
-3
View File
@@ -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)
+1 -11
View File
@@ -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>
-3
View File
@@ -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
View File
@@ -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>
+38
View File
@@ -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 */
-8
View File
@@ -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 */
-3
View File
@@ -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
View File
@@ -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>
-3
View File
@@ -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)
+2 -2
View File
@@ -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
View File
@@ -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
{
+1 -3
View File
@@ -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; \
-3
View File
@@ -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
View File
@@ -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
{
-3
View File
@@ -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
View File
@@ -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>
+2 -1
View File
@@ -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. */
+13
View File
@@ -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, ());
+1 -11
View File
@@ -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
-10
View File
@@ -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>
-3
View File
@@ -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)
+1 -11
View File
@@ -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>
-3
View File
@@ -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