mirror of
git://sourceware.org/git/glibc.git
synced 2026-09-09 23:58:37 +08:00
Compare commits
104
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ceeb0740ed | ||
|
|
24adabbe17 | ||
|
|
8224a992e1 | ||
|
|
ed739093d1 | ||
|
|
fec2dc4089 | ||
|
|
6636d6f4fe | ||
|
|
06e821cfff | ||
|
|
ccae0be673 | ||
|
|
f0a8620883 | ||
|
|
058b5a41d5 | ||
|
|
afb035f50b | ||
|
|
254269d6a9 | ||
|
|
d7d49b0841 | ||
|
|
fa9a646079 | ||
|
|
d848d80256 | ||
|
|
1ec838a143 | ||
|
|
2eb71adc3f | ||
|
|
e124685d61 | ||
|
|
810c1eaf41 | ||
|
|
52f47e52a6 | ||
|
|
24d5e1f7a7 | ||
|
|
311b5e3144 | ||
|
|
5b676a963e | ||
|
|
8822744953 | ||
|
|
679988f022 | ||
|
|
41f8b8f92e | ||
|
|
4a1fd9645d | ||
|
|
6a7831994e | ||
|
|
ae4ff739ea | ||
|
|
1436096a43 | ||
|
|
9dc6f738ae | ||
|
|
ddce84f1c0 | ||
|
|
ac5625f7c9 | ||
|
|
6def9198c3 | ||
|
|
45ce3f30e3 | ||
|
|
0fb14a3850 | ||
|
|
cf70de6362 | ||
|
|
bb433427a5 | ||
|
|
3501fea690 | ||
|
|
bab150583d | ||
|
|
321e1cef26 | ||
|
|
c2fba3b047 | ||
|
|
1915d6d182 | ||
|
|
e6eea05ee7 | ||
|
|
f222547511 | ||
|
|
bdce95930e | ||
|
|
25a34b0ac1 | ||
|
|
2143af6a47 | ||
|
|
a37d61a662 | ||
|
|
1a8a7c1295 | ||
|
|
24e2b1cede | ||
|
|
bbea74b299 | ||
|
|
a824d60958 | ||
|
|
80f87443ee | ||
|
|
c4294bd862 | ||
|
|
c87db3fcbd | ||
|
|
68302147ee | ||
|
|
90c0f166e9 | ||
|
|
4cf055a2a3 | ||
|
|
d603d94994 | ||
|
|
7fa9775594 | ||
|
|
075b2665b1 | ||
|
|
1e5ac8a1da | ||
|
|
730244f49a | ||
|
|
1e51b4d367 | ||
|
|
f233c608d1 | ||
|
|
49203a513f | ||
|
|
888d9a0146 | ||
|
|
927170dd59 | ||
|
|
2a71cf4096 | ||
|
|
a5c2f42566 | ||
|
|
f69ae17e84 | ||
|
|
4c4b3cbb46 | ||
|
|
2d1f679018 | ||
|
|
8a756c076e | ||
|
|
f8020794ae | ||
|
|
05d2606fa1 | ||
|
|
c5aae1035c | ||
|
|
e5bcbfc23b | ||
|
|
42a496388d | ||
|
|
28a87e0274 | ||
|
|
5769d5d17c | ||
|
|
f1e182acaa | ||
|
|
146b58d11f | ||
|
|
0eb234232e | ||
|
|
d93f04543c | ||
|
|
3a188eb4e6 | ||
|
|
73f158cef5 | ||
|
|
317da342ba | ||
|
|
33ab2ad58e | ||
|
|
b4456470a6 | ||
|
|
3ac64b00b5 | ||
|
|
0594fd0546 | ||
|
|
63ed4db4b4 | ||
|
|
9d1399e89d | ||
|
|
f23d7d2a84 | ||
|
|
0a321a461c | ||
|
|
d27dabc996 | ||
|
|
591b7e37e6 | ||
|
|
f0029f1bb3 | ||
|
|
6094fc2cf7 | ||
|
|
e742928c15 | ||
|
|
d3a793f7ee | ||
|
|
792c8ddc60 |
@@ -4,6 +4,48 @@ 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.23.1
|
||||
|
||||
Security related changes:
|
||||
|
||||
* The getnetbyname implementation in nss_dns had a potentially unbounded
|
||||
alloca call (in the form of a call to strdupa), leading to a stack
|
||||
overflow (stack exhaustion) and a crash if getnetbyname is invoked
|
||||
on a very long name. (CVE-2016-3075)
|
||||
|
||||
* The glob function suffered from a stack-based buffer overflow when it was
|
||||
called with the GLOB_ALTDIRFUNC flag and encountered a long file name.
|
||||
Reported by Alexander Cherepanov. (CVE-2016-1234)
|
||||
|
||||
* The Sun RPC UDP client could exhaust all available stack space when
|
||||
flooded with crafted ICMP and UDP messages. Reported by Aldy Hernandez'
|
||||
alloca plugin for GCC. (CVE-2016-4429)
|
||||
|
||||
* On ARM EABI (32-bit), generating a backtrace for execution contexts which
|
||||
have been created with makecontext could fail to terminate due to a
|
||||
missing .cantunwind annotation. This has been observed to lead to a hang
|
||||
(denial of service) in some Go applications compiled with gccgo. Reported
|
||||
by Andreas Schwab. (CVE-2016-6323)
|
||||
|
||||
The following bugs are resolved with this release:
|
||||
|
||||
[19679] gcc-4.9.3 C++ exception handling broken due to unaligned stack
|
||||
[19758] Or bit_Prefer_MAP_32BIT_EXEC in EXTRA_LD_ENVVARS
|
||||
[19759] Don't inline mempcpy for x86
|
||||
[19762] Use HAS_ARCH_FEATURE with Fast_Rep_String
|
||||
[19791] Assertion failure in res_query.c with un-connectable name server
|
||||
addresses
|
||||
[19792] MIPS: backtrace yields infinite backtrace with makecontext
|
||||
[19822] libm.so install clobbers old version
|
||||
[19879] network: nss_dns: Stack overflow in getnetbyname implementation
|
||||
(CVE-2016-3075)
|
||||
[20177] $dp is not initialized correctly in sysdeps/hppa/start.S
|
||||
[20357] Incorrect cos result for 1.5174239687223976
|
||||
[21209] Ignore and remove LD_HWCAP_MASK for AT_SECURE programs
|
||||
[21289] Fix symbol redirect for fts_set
|
||||
[21624] Unsafe alloca allows local attackers to alias stack and heap (CVE-2017-1000366)
|
||||
|
||||
|
||||
Version 2.23
|
||||
|
||||
@@ -38,7 +80,7 @@ Version 2.23
|
||||
unnecessary serialization of memory allocation requests across threads.
|
||||
The defect is now corrected. Users should see a substantial increase in
|
||||
the concurent throughput of allocation requests for applications which
|
||||
trigger this bug. Affected applications typically create create and
|
||||
trigger this bug. Affected applications typically create and
|
||||
destroy threads frequently. (Bug 19048 was reported and analyzed by
|
||||
Ericsson.)
|
||||
|
||||
|
||||
+4
-15
@@ -29,21 +29,6 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef __attribute__
|
||||
/* This feature is available in gcc versions 2.5 and later. */
|
||||
# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || \
|
||||
defined __STRICT_ANSI__
|
||||
# define __attribute__(Spec) /* empty */
|
||||
# endif
|
||||
/* The __-protected variants of `format' and `printf' attributes
|
||||
are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */
|
||||
# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) || \
|
||||
defined __STRICT_ANSI__
|
||||
# define __format__ format
|
||||
# define __printf__ printf
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined (__GNU_LIBRARY__) && defined (HAVE_LINEWRAP_H)
|
||||
/* line_wrap_stream is available, so use that. */
|
||||
#define ARGP_FMTSTREAM_USE_LINEWRAP
|
||||
@@ -111,6 +96,8 @@ struct argp_fmtstream
|
||||
|
||||
typedef struct argp_fmtstream *argp_fmtstream_t;
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
/* Return an argp_fmtstream that outputs to STREAM, and which prefixes lines
|
||||
written on it with LMARGIN spaces and limits them to RMARGIN columns
|
||||
total. If WMARGIN >= 0, words that extend past RMARGIN are wrapped by
|
||||
@@ -297,6 +284,8 @@ __argp_fmtstream_point (argp_fmtstream_t __fs)
|
||||
|
||||
#endif /* __OPTIMIZE__ */
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /* ARGP_FMTSTREAM_USE_LINEWRAP */
|
||||
|
||||
#endif /* argp-fmtstream.h */
|
||||
|
||||
+2
-40
@@ -28,48 +28,12 @@
|
||||
#define __need_error_t
|
||||
#include <errno.h>
|
||||
|
||||
#ifndef __THROW
|
||||
# define __THROW
|
||||
#endif
|
||||
#ifndef __NTH
|
||||
# define __NTH(fct) fct __THROW
|
||||
#endif
|
||||
|
||||
#ifndef __attribute__
|
||||
/* This feature is available in gcc versions 2.5 and later. */
|
||||
# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || \
|
||||
defined __STRICT_ANSI__
|
||||
# define __attribute__(Spec) /* empty */
|
||||
# endif
|
||||
/* The __-protected variants of `format' and `printf' attributes
|
||||
are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */
|
||||
# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) || \
|
||||
defined __STRICT_ANSI__
|
||||
# define __format__ format
|
||||
# define __printf__ printf
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* GCC 2.95 and later have "__restrict"; C99 compilers have
|
||||
"restrict", and "configure" may have defined "restrict". */
|
||||
#ifndef __restrict
|
||||
# if ! (2 < __GNUC__ || (2 == __GNUC__ && 95 <= __GNUC_MINOR__))
|
||||
# if defined restrict || 199901L <= __STDC_VERSION__
|
||||
# define __restrict restrict
|
||||
# else
|
||||
# define __restrict
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef __error_t_defined
|
||||
typedef int error_t;
|
||||
# define __error_t_defined
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
__BEGIN_DECLS
|
||||
|
||||
/* A description of a particular option. A pointer to an array of
|
||||
these is passed in the OPTIONS field of an argp structure. Each option
|
||||
@@ -590,8 +554,6 @@ __NTH (__option_is_end (const struct argp_option *__opt))
|
||||
# endif
|
||||
#endif /* Use extern inlines. */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
__END_DECLS
|
||||
|
||||
#endif /* argp.h */
|
||||
|
||||
+4
-1
@@ -1,4 +1,4 @@
|
||||
/* Definition of `struct sockaddr_*' common members. Generic/4.2 BSD version.
|
||||
/* Definition of struct sockaddr_* common members and sizes, generic version.
|
||||
Copyright (C) 1995-2016 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
@@ -36,4 +36,7 @@ typedef unsigned short int sa_family_t;
|
||||
|
||||
#define __SOCKADDR_COMMON_SIZE (sizeof (unsigned short int))
|
||||
|
||||
/* Size of struct sockaddr_storage. */
|
||||
#define _SS_SIZE 128
|
||||
|
||||
#endif /* bits/sockaddr.h */
|
||||
|
||||
+4
-4
@@ -152,20 +152,20 @@ struct sockaddr
|
||||
|
||||
|
||||
/* Structure large enough to hold any socket address (with the historical
|
||||
exception of AF_UNIX). We reserve 128 bytes. */
|
||||
exception of AF_UNIX). */
|
||||
#if ULONG_MAX > 0xffffffff
|
||||
# define __ss_aligntype __uint64_t
|
||||
#else
|
||||
# define __ss_aligntype __uint32_t
|
||||
#endif
|
||||
#define _SS_SIZE 128
|
||||
#define _SS_PADSIZE (_SS_SIZE - (2 * sizeof (__ss_aligntype)))
|
||||
#define _SS_PADSIZE \
|
||||
(_SS_SIZE - __SOCKADDR_COMMON_SIZE - sizeof (__ss_aligntype))
|
||||
|
||||
struct sockaddr_storage
|
||||
{
|
||||
__SOCKADDR_COMMON (ss_); /* Address family, etc. */
|
||||
__ss_aligntype __ss_align; /* Force desired alignment. */
|
||||
char __ss_padding[_SS_PADSIZE];
|
||||
__ss_aligntype __ss_align; /* Force desired alignment. */
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -3864,7 +3864,7 @@ if test -z "$enable_hacker_mode" && test x"$libc_config_ok" != xyes; then
|
||||
*** The GNU C library is currently unavailable for this platform.
|
||||
*** If you are interested in seeing glibc on this platform visit
|
||||
*** the \"How to submit a new port\" in the wiki:
|
||||
*** https://sourceware.org/glibc/wiki/HomePage#Development
|
||||
*** https://sourceware.org/glibc/wiki/#Development
|
||||
*** and join the community!" "$LINENO" 5
|
||||
;;
|
||||
esac
|
||||
@@ -6252,12 +6252,14 @@ echo >&5 "libc_undefs='$libc_undefs'"
|
||||
# symbols (resolved by the linker), so filter out unknown symbols.
|
||||
# This will fail to produce the correct result if the compiler
|
||||
# defaults to -fstack-protector but this produces an undefined symbol
|
||||
# other than __stack_chk_fail. However, compilers like that have not
|
||||
# been encountered in practice.
|
||||
libc_undefs=`echo "$libc_undefs" | egrep '^(foobar|__stack_chk_fail)$'`
|
||||
# other than __stack_chk_fail or __stack_chk_fail_local. However,
|
||||
# compilers like that have not been encountered in practice.
|
||||
libc_undefs=`echo "$libc_undefs" | \
|
||||
egrep '^(foobar|__stack_chk_fail|__stack_chk_fail_local)$'`
|
||||
case "$libc_undefs" in
|
||||
foobar) libc_cv_predef_stack_protector=no ;;
|
||||
'__stack_chk_fail
|
||||
foobar'|'__stack_chk_fail_local
|
||||
foobar') libc_cv_predef_stack_protector=yes ;;
|
||||
*) as_fn_error $? "unexpected symbols in test: $libc_undefs" "$LINENO" 5 ;;
|
||||
esac
|
||||
|
||||
+5
-3
@@ -1603,12 +1603,14 @@ echo >&AS_MESSAGE_LOG_FD "libc_undefs='$libc_undefs'"
|
||||
# symbols (resolved by the linker), so filter out unknown symbols.
|
||||
# This will fail to produce the correct result if the compiler
|
||||
# defaults to -fstack-protector but this produces an undefined symbol
|
||||
# other than __stack_chk_fail. However, compilers like that have not
|
||||
# been encountered in practice.
|
||||
libc_undefs=`echo "$libc_undefs" | egrep '^(foobar|__stack_chk_fail)$'`
|
||||
# other than __stack_chk_fail or __stack_chk_fail_local. However,
|
||||
# compilers like that have not been encountered in practice.
|
||||
libc_undefs=`echo "$libc_undefs" | \
|
||||
egrep '^(foobar|__stack_chk_fail|__stack_chk_fail_local)$'`
|
||||
case "$libc_undefs" in
|
||||
foobar) libc_cv_predef_stack_protector=no ;;
|
||||
'__stack_chk_fail
|
||||
foobar'|'__stack_chk_fail_local
|
||||
foobar') libc_cv_predef_stack_protector=yes ;;
|
||||
*) AC_MSG_ERROR([unexpected symbols in test: $libc_undefs]) ;;
|
||||
esac],
|
||||
|
||||
+1
-1
@@ -175,7 +175,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);
|
||||
|
||||
|
||||
+6
-1
@@ -163,7 +163,8 @@ endif
|
||||
endif
|
||||
ifeq ($(run-built-tests),yes)
|
||||
tests-special += $(objpfx)tst-leaks1-mem.out \
|
||||
$(objpfx)tst-leaks1-static-mem.out $(objpfx)noload-mem.out
|
||||
$(objpfx)tst-leaks1-static-mem.out $(objpfx)noload-mem.out \
|
||||
$(objpfx)tst-ldconfig-X.out
|
||||
endif
|
||||
tlsmod17a-suffixes = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
||||
tlsmod18a-suffixes = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
||||
@@ -1252,3 +1253,7 @@ $(objpfx)tst-prelink-cmp.out: tst-prelink.exp \
|
||||
$(objpfx)tst-prelink-conflict.out
|
||||
cmp $^ > $@; \
|
||||
$(evaluate-test)
|
||||
|
||||
$(objpfx)tst-ldconfig-X.out : tst-ldconfig-X.sh $(objpfx)ldconfig
|
||||
$(SHELL) $< '$(common-objpfx)' '$(test-wrapper)' '$(test-wrapper-env)' > $@; \
|
||||
$(evaluate-test)
|
||||
|
||||
+97
-63
@@ -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;
|
||||
}
|
||||
|
||||
@@ -494,7 +521,7 @@ _dl_allocate_tls_init (void *result)
|
||||
maxgen = MAX (maxgen, listp->slotinfo[cnt].gen);
|
||||
|
||||
dtv[map->l_tls_modid].pointer.val = TLS_DTV_UNALLOCATED;
|
||||
dtv[map->l_tls_modid].pointer.is_static = false;
|
||||
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)
|
||||
@@ -551,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)
|
||||
|
||||
@@ -594,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 (max_align_t))
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -678,12 +721,9 @@ _dl_update_slotinfo (unsigned long int req_modid)
|
||||
{
|
||||
/* 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))
|
||||
free (dtv[total + cnt].pointer.val);
|
||||
free (dtv[total + cnt].pointer.to_free);
|
||||
dtv[total + cnt].pointer.val = TLS_DTV_UNALLOCATED;
|
||||
dtv[total + cnt].pointer.is_static = false;
|
||||
dtv[total + cnt].pointer.to_free = NULL;
|
||||
}
|
||||
|
||||
continue;
|
||||
@@ -708,16 +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);
|
||||
|
||||
free (dtv[modid].pointer.to_free);
|
||||
dtv[modid].pointer.val = TLS_DTV_UNALLOCATED;
|
||||
dtv[modid].pointer.is_static = false;
|
||||
dtv[modid].pointer.to_free = NULL;
|
||||
|
||||
if (modid == req_modid)
|
||||
the_map = map;
|
||||
@@ -780,7 +813,7 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map)
|
||||
#endif
|
||||
__rtld_lock_unlock_recursive (GL(dl_load_lock));
|
||||
|
||||
dtv[GET_ADDR_MODULE].pointer.is_static = true;
|
||||
dtv[GET_ADDR_MODULE].pointer.to_free = NULL;
|
||||
dtv[GET_ADDR_MODULE].pointer.val = p;
|
||||
|
||||
return (char *) p + GET_ADDR_OFFSET;
|
||||
@@ -788,10 +821,11 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map)
|
||||
else
|
||||
__rtld_lock_unlock_recursive (GL(dl_load_lock));
|
||||
}
|
||||
void *p = dtv[GET_ADDR_MODULE].pointer.val = allocate_and_init (the_map);
|
||||
assert (!dtv[GET_ADDR_MODULE].pointer.is_static);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+4
-3
@@ -100,7 +100,8 @@ int opt_format = 1;
|
||||
/* Build cache. */
|
||||
static int opt_build_cache = 1;
|
||||
|
||||
/* Generate links. */
|
||||
/* Enable symbolic link processing. If set, create or update symbolic
|
||||
links, and remove stale symbolic links. */
|
||||
static int opt_link = 1;
|
||||
|
||||
/* Only process directories specified on the command line. */
|
||||
@@ -141,7 +142,7 @@ static const struct argp_option options[] =
|
||||
{ "print-cache", 'p', NULL, 0, N_("Print cache"), 0},
|
||||
{ "verbose", 'v', NULL, 0, N_("Generate verbose messages"), 0},
|
||||
{ NULL, 'N', NULL, 0, N_("Don't build cache"), 0},
|
||||
{ NULL, 'X', NULL, 0, N_("Don't generate links"), 0},
|
||||
{ NULL, 'X', NULL, 0, N_("Don't update symbolic links"), 0},
|
||||
{ NULL, 'r', N_("ROOT"), 0, N_("Change to and use ROOT as root directory"), 0},
|
||||
{ NULL, 'C', N_("CACHE"), 0, N_("Use CACHE as cache file"), 0},
|
||||
{ NULL, 'f', N_("CONF"), 0, N_("Use CONF as configuration file"), 0},
|
||||
@@ -800,7 +801,7 @@ search_dir (const struct dir_entry *entry)
|
||||
error (0, errno, _("Cannot stat %s"), file_name);
|
||||
|
||||
/* Remove stale symlinks. */
|
||||
if (strstr (direntry->d_name, ".so."))
|
||||
if (opt_link && strstr (direntry->d_name, ".so."))
|
||||
unlink (real_file_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
+165
-33
@@ -99,14 +99,121 @@ uintptr_t __pointer_chk_guard_local
|
||||
strong_alias (__pointer_chk_guard_local, __pointer_chk_guard)
|
||||
#endif
|
||||
|
||||
/* Length limits for names and paths, to protect the dynamic linker,
|
||||
particularly when __libc_enable_secure is active. */
|
||||
#ifdef NAME_MAX
|
||||
# define SECURE_NAME_LIMIT NAME_MAX
|
||||
#else
|
||||
# define SECURE_NAME_LIMIT 255
|
||||
#endif
|
||||
#ifdef PATH_MAX
|
||||
# define SECURE_PATH_LIMIT PATH_MAX
|
||||
#else
|
||||
# define SECURE_PATH_LIMIT 1024
|
||||
#endif
|
||||
|
||||
/* List of auditing DSOs. */
|
||||
/* Check that AT_SECURE=0, or that the passed name does not contain
|
||||
directories and is not overly long. Reject empty names
|
||||
unconditionally. */
|
||||
static bool
|
||||
dso_name_valid_for_suid (const char *p)
|
||||
{
|
||||
if (__glibc_unlikely (__libc_enable_secure))
|
||||
{
|
||||
/* Ignore pathnames with directories for AT_SECURE=1
|
||||
programs, and also skip overlong names. */
|
||||
size_t len = strlen (p);
|
||||
if (len >= SECURE_NAME_LIMIT || memchr (p, '/', len) != NULL)
|
||||
return false;
|
||||
}
|
||||
return *p != '\0';
|
||||
}
|
||||
|
||||
/* LD_AUDIT variable contents. Must be processed before the
|
||||
audit_list below. */
|
||||
const char *audit_list_string;
|
||||
|
||||
/* Cyclic list of auditing DSOs. audit_list->next is the first
|
||||
element. */
|
||||
static struct audit_list
|
||||
{
|
||||
const char *name;
|
||||
struct audit_list *next;
|
||||
} *audit_list;
|
||||
|
||||
/* Iterator for audit_list_string followed by audit_list. */
|
||||
struct audit_list_iter
|
||||
{
|
||||
/* Tail of audit_list_string still needing processing, or NULL. */
|
||||
const char *audit_list_tail;
|
||||
|
||||
/* The list element returned in the previous iteration. NULL before
|
||||
the first element. */
|
||||
struct audit_list *previous;
|
||||
|
||||
/* Scratch buffer for returning a name which is part of
|
||||
audit_list_string. */
|
||||
char fname[SECURE_NAME_LIMIT];
|
||||
};
|
||||
|
||||
/* Initialize an audit list iterator. */
|
||||
static void
|
||||
audit_list_iter_init (struct audit_list_iter *iter)
|
||||
{
|
||||
iter->audit_list_tail = audit_list_string;
|
||||
iter->previous = NULL;
|
||||
}
|
||||
|
||||
/* Iterate through both audit_list_string and audit_list. */
|
||||
static const char *
|
||||
audit_list_iter_next (struct audit_list_iter *iter)
|
||||
{
|
||||
if (iter->audit_list_tail != NULL)
|
||||
{
|
||||
/* First iterate over audit_list_string. */
|
||||
while (*iter->audit_list_tail != '\0')
|
||||
{
|
||||
/* Split audit list at colon. */
|
||||
size_t len = strcspn (iter->audit_list_tail, ":");
|
||||
if (len > 0 && len < sizeof (iter->fname))
|
||||
{
|
||||
memcpy (iter->fname, iter->audit_list_tail, len);
|
||||
iter->fname[len] = '\0';
|
||||
}
|
||||
else
|
||||
/* Do not return this name to the caller. */
|
||||
iter->fname[0] = '\0';
|
||||
|
||||
/* Skip over the substring and the following delimiter. */
|
||||
iter->audit_list_tail += len;
|
||||
if (*iter->audit_list_tail == ':')
|
||||
++iter->audit_list_tail;
|
||||
|
||||
/* If the name is valid, return it. */
|
||||
if (dso_name_valid_for_suid (iter->fname))
|
||||
return iter->fname;
|
||||
/* Otherwise, wrap around and try the next name. */
|
||||
}
|
||||
/* Fall through to the procesing of audit_list. */
|
||||
}
|
||||
|
||||
if (iter->previous == NULL)
|
||||
{
|
||||
if (audit_list == NULL)
|
||||
/* No pre-parsed audit list. */
|
||||
return NULL;
|
||||
/* Start of audit list. The first list element is at
|
||||
audit_list->next (cyclic list). */
|
||||
iter->previous = audit_list->next;
|
||||
return iter->previous->name;
|
||||
}
|
||||
if (iter->previous == audit_list)
|
||||
/* Cyclic list wrap-around. */
|
||||
return NULL;
|
||||
iter->previous = iter->previous->next;
|
||||
return iter->previous->name;
|
||||
}
|
||||
|
||||
#ifndef HAVE_INLINED_SYSCALLS
|
||||
/* Set nonzero during loading and initialization of executable and
|
||||
libraries, cleared before the executable's entry point runs. This
|
||||
@@ -730,6 +837,42 @@ static const char *preloadlist attribute_relro;
|
||||
/* Nonzero if information about versions has to be printed. */
|
||||
static int version_info attribute_relro;
|
||||
|
||||
/* The LD_PRELOAD environment variable gives list of libraries
|
||||
separated by white space or colons that are loaded before the
|
||||
executable's dependencies and prepended to the global scope list.
|
||||
(If the binary is running setuid all elements containing a '/' are
|
||||
ignored since it is insecure.) Return the number of preloads
|
||||
performed. */
|
||||
unsigned int
|
||||
handle_ld_preload (const char *preloadlist, struct link_map *main_map)
|
||||
{
|
||||
unsigned int npreloads = 0;
|
||||
const char *p = preloadlist;
|
||||
char fname[SECURE_PATH_LIMIT];
|
||||
|
||||
while (*p != '\0')
|
||||
{
|
||||
/* Split preload list at space/colon. */
|
||||
size_t len = strcspn (p, " :");
|
||||
if (len > 0 && len < sizeof (fname))
|
||||
{
|
||||
memcpy (fname, p, len);
|
||||
fname[len] = '\0';
|
||||
}
|
||||
else
|
||||
fname[0] = '\0';
|
||||
|
||||
/* Skip over the substring and the following delimiter. */
|
||||
p += len;
|
||||
if (*p != '\0')
|
||||
++p;
|
||||
|
||||
if (dso_name_valid_for_suid (fname))
|
||||
npreloads += do_preload (fname, main_map, "LD_PRELOAD");
|
||||
}
|
||||
return npreloads;
|
||||
}
|
||||
|
||||
static void
|
||||
dl_main (const ElfW(Phdr) *phdr,
|
||||
ElfW(Word) phnum,
|
||||
@@ -1257,11 +1400,13 @@ of this helper program; chances are you did not intend to run this program.\n\
|
||||
GL(dl_rtld_map).l_tls_modid = _dl_next_tls_modid ();
|
||||
|
||||
/* If we have auditing DSOs to load, do it now. */
|
||||
if (__glibc_unlikely (audit_list != NULL))
|
||||
bool need_security_init = true;
|
||||
if (__glibc_unlikely (audit_list != NULL)
|
||||
|| __glibc_unlikely (audit_list_string != NULL))
|
||||
{
|
||||
/* Iterate over all entries in the list. The order is important. */
|
||||
struct audit_ifaces *last_audit = NULL;
|
||||
struct audit_list *al = audit_list->next;
|
||||
struct audit_list_iter al_iter;
|
||||
audit_list_iter_init (&al_iter);
|
||||
|
||||
/* Since we start using the auditing DSOs right away we need to
|
||||
initialize the data structures now. */
|
||||
@@ -1272,9 +1417,14 @@ of this helper program; chances are you did not intend to run this program.\n\
|
||||
use different values (especially the pointer guard) and will
|
||||
fail later on. */
|
||||
security_init ();
|
||||
need_security_init = false;
|
||||
|
||||
do
|
||||
while (true)
|
||||
{
|
||||
const char *name = audit_list_iter_next (&al_iter);
|
||||
if (name == NULL)
|
||||
break;
|
||||
|
||||
int tls_idx = GL(dl_tls_max_dtv_idx);
|
||||
|
||||
/* Now it is time to determine the layout of the static TLS
|
||||
@@ -1283,7 +1433,7 @@ of this helper program; chances are you did not intend to run this program.\n\
|
||||
no DF_STATIC_TLS bit is set. The reason is that we know
|
||||
glibc will use the static model. */
|
||||
struct dlmopen_args dlmargs;
|
||||
dlmargs.fname = al->name;
|
||||
dlmargs.fname = name;
|
||||
dlmargs.map = NULL;
|
||||
|
||||
const char *objname;
|
||||
@@ -1296,7 +1446,7 @@ of this helper program; chances are you did not intend to run this program.\n\
|
||||
not_loaded:
|
||||
_dl_error_printf ("\
|
||||
ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
|
||||
al->name, err_str);
|
||||
name, err_str);
|
||||
if (malloced)
|
||||
free ((char *) err_str);
|
||||
}
|
||||
@@ -1400,10 +1550,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
|
||||
goto not_loaded;
|
||||
}
|
||||
}
|
||||
|
||||
al = al->next;
|
||||
}
|
||||
while (al != audit_list->next);
|
||||
|
||||
/* If we have any auditing modules, announce that we already
|
||||
have two objects loaded. */
|
||||
@@ -1481,23 +1628,8 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
|
||||
|
||||
if (__glibc_unlikely (preloadlist != NULL))
|
||||
{
|
||||
/* The LD_PRELOAD environment variable gives list of libraries
|
||||
separated by white space or colons that are loaded before the
|
||||
executable's dependencies and prepended to the global scope
|
||||
list. If the binary is running setuid all elements
|
||||
containing a '/' are ignored since it is insecure. */
|
||||
char *list = strdupa (preloadlist);
|
||||
char *p;
|
||||
|
||||
HP_TIMING_NOW (start);
|
||||
|
||||
/* Prevent optimizing strsep. Speed is not important here. */
|
||||
while ((p = (strsep) (&list, " :")) != NULL)
|
||||
if (p[0] != '\0'
|
||||
&& (__builtin_expect (! __libc_enable_secure, 1)
|
||||
|| strchr (p, '/') == NULL))
|
||||
npreloads += do_preload (p, main_map, "LD_PRELOAD");
|
||||
|
||||
npreloads += handle_ld_preload (preloadlist, main_map);
|
||||
HP_TIMING_NOW (stop);
|
||||
HP_TIMING_DIFF (diff, start, stop);
|
||||
HP_TIMING_ACCUM_NT (load_time, diff);
|
||||
@@ -1682,7 +1814,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
|
||||
if (tcbp == NULL)
|
||||
tcbp = init_tls ();
|
||||
|
||||
if (__glibc_likely (audit_list == NULL))
|
||||
if (__glibc_likely (need_security_init))
|
||||
/* Initialize security features. But only if we have not done it
|
||||
earlier. */
|
||||
security_init ();
|
||||
@@ -2313,9 +2445,7 @@ process_dl_audit (char *str)
|
||||
char *p;
|
||||
|
||||
while ((p = (strsep) (&str, ":")) != NULL)
|
||||
if (p[0] != '\0'
|
||||
&& (__builtin_expect (! __libc_enable_secure, 1)
|
||||
|| strchr (p, '/') == NULL))
|
||||
if (dso_name_valid_for_suid (p))
|
||||
{
|
||||
/* This is using the local malloc, not the system malloc. The
|
||||
memory can never be freed. */
|
||||
@@ -2379,7 +2509,7 @@ process_envvars (enum mode *modep)
|
||||
break;
|
||||
}
|
||||
if (memcmp (envline, "AUDIT", 5) == 0)
|
||||
process_dl_audit (&envline[6]);
|
||||
audit_list_string = &envline[6];
|
||||
break;
|
||||
|
||||
case 7:
|
||||
@@ -2423,7 +2553,8 @@ process_envvars (enum mode *modep)
|
||||
|
||||
case 10:
|
||||
/* Mask for the important hardware capabilities. */
|
||||
if (memcmp (envline, "HWCAP_MASK", 10) == 0)
|
||||
if (!__libc_enable_secure
|
||||
&& memcmp (envline, "HWCAP_MASK", 10) == 0)
|
||||
GLRO(dl_hwcap_mask) = __strtoul_internal (&envline[11], NULL,
|
||||
0, 0);
|
||||
break;
|
||||
@@ -2437,7 +2568,8 @@ process_envvars (enum mode *modep)
|
||||
|
||||
case 12:
|
||||
/* The library search path. */
|
||||
if (memcmp (envline, "LIBRARY_PATH", 12) == 0)
|
||||
if (!__libc_enable_secure
|
||||
&& memcmp (envline, "LIBRARY_PATH", 12) == 0)
|
||||
{
|
||||
library_path = &envline[13];
|
||||
break;
|
||||
|
||||
@@ -164,11 +164,11 @@ makesymlinks (const char *file)
|
||||
static int
|
||||
makesymlink (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))
|
||||
{
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
#!/bin/sh
|
||||
# Test that ldconfig -X does not remove stale symbolic links.
|
||||
# Copyright (C) 2000-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/>.
|
||||
|
||||
set -ex
|
||||
|
||||
common_objpfx=$1
|
||||
test_wrapper_env=$2
|
||||
run_program_env=$3
|
||||
|
||||
testroot="${common_objpfx}elf/bug19610-test-directory"
|
||||
cleanup () {
|
||||
rm -rf "$testroot"
|
||||
}
|
||||
trap cleanup 0
|
||||
|
||||
rm -rf "$testroot"
|
||||
mkdir -p $testroot/lib $testroot/etc
|
||||
|
||||
# Relative symbolic link target.
|
||||
ln -s libdoesnotexist.so.1.1 $testroot/lib/libdoesnotexist.so.1
|
||||
|
||||
# Absolute symbolic link target.
|
||||
ln -s $testroot/opt/sw/lib/libdoesnotexist2.so.1.1 $testroot/lib/
|
||||
|
||||
errors=0
|
||||
check_files () {
|
||||
for name in libdoesnotexist.so.1 libdoesnotexist2.so.1.1 ; do
|
||||
path="$testroot/lib/$name"
|
||||
if test ! -h $path ; then
|
||||
echo "error: missing file: $path"
|
||||
errors=1
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
check_files
|
||||
|
||||
${test_wrapper_env} \
|
||||
${run_program_env} \
|
||||
${common_objpfx}elf/ldconfig -X -f /dev/null \
|
||||
-C $testroot/etc/ld.so.cache \
|
||||
$testroot/lib
|
||||
|
||||
check_files
|
||||
|
||||
exit $errors
|
||||
+1
-1
@@ -28,7 +28,7 @@ extra-libs-others = $(extra-libs)
|
||||
subdir-dirs = nss_hesiod
|
||||
vpath %.c nss_hesiod
|
||||
|
||||
libnss_hesiod-routines := hesiod hesiod-grp hesiod-init hesiod-proto \
|
||||
libnss_hesiod-routines := hesiod hesiod-grp hesiod-proto \
|
||||
hesiod-pwd hesiod-service
|
||||
# Build only shared library
|
||||
libnss_hesiod-inhibit-o = $(filter-out .os,$(object-suffixes))
|
||||
|
||||
+19
-70
@@ -1,6 +1,19 @@
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static const char rcsid[] = "$BINDId: hesiod.c,v 1.21 2000/02/28 14:51:08 vixie Exp $";
|
||||
#endif
|
||||
/* Copyright (C) 1997-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) 1996,1999 by Internet Software Consortium.
|
||||
@@ -52,18 +65,9 @@ static const char rcsid[] = "$BINDId: hesiod.c,v 1.21 2000/02/28 14:51:08 vixie
|
||||
|
||||
/* Forward */
|
||||
|
||||
int hesiod_init(void **context);
|
||||
void hesiod_end(void *context);
|
||||
char * hesiod_to_bind(void *context, const char *name,
|
||||
const char *type);
|
||||
char ** hesiod_resolve(void *context, const char *name,
|
||||
const char *type);
|
||||
void hesiod_free_list(void *context, char **list);
|
||||
|
||||
static int parse_config_file(struct hesiod_p *ctx, const char *filename);
|
||||
static char ** get_txt_records(struct hesiod_p *ctx, int class,
|
||||
const char *name);
|
||||
static int init(struct hesiod_p *ctx);
|
||||
|
||||
/* Public */
|
||||
|
||||
@@ -82,7 +86,6 @@ hesiod_init(void **context) {
|
||||
|
||||
ctx->LHS = NULL;
|
||||
ctx->RHS = NULL;
|
||||
ctx->res = NULL;
|
||||
/* Set default query classes. */
|
||||
ctx->classes[0] = C_IN;
|
||||
ctx->classes[1] = C_HS;
|
||||
@@ -131,11 +134,6 @@ hesiod_init(void **context) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (res_ninit(ctx->res) < 0)
|
||||
goto cleanup;
|
||||
#endif
|
||||
|
||||
*context = ctx;
|
||||
return (0);
|
||||
|
||||
@@ -152,12 +150,8 @@ hesiod_end(void *context) {
|
||||
struct hesiod_p *ctx = (struct hesiod_p *) context;
|
||||
int save_errno = errno;
|
||||
|
||||
if (ctx->res)
|
||||
res_nclose(ctx->res);
|
||||
free(ctx->RHS);
|
||||
free(ctx->LHS);
|
||||
if (ctx->res && ctx->free_res)
|
||||
(*ctx->free_res)(ctx->res);
|
||||
free(ctx);
|
||||
__set_errno(save_errno);
|
||||
}
|
||||
@@ -232,10 +226,6 @@ hesiod_resolve(void *context, const char *name, const char *type) {
|
||||
|
||||
if (bindname == NULL)
|
||||
return (NULL);
|
||||
if (init(ctx) == -1) {
|
||||
free(bindname);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
retvec = get_txt_records(ctx, ctx->classes[0], bindname);
|
||||
|
||||
@@ -365,13 +355,13 @@ get_txt_records(struct hesiod_p *ctx, int class, const char *name) {
|
||||
/*
|
||||
* Construct the query and send it.
|
||||
*/
|
||||
n = res_nmkquery(ctx->res, QUERY, name, class, T_TXT, NULL, 0,
|
||||
n = res_mkquery(QUERY, name, class, T_TXT, NULL, 0,
|
||||
NULL, qbuf, MAX_HESRESP);
|
||||
if (n < 0) {
|
||||
__set_errno(EMSGSIZE);
|
||||
return (NULL);
|
||||
}
|
||||
n = res_nsend(ctx->res, qbuf, n, abuf, MAX_HESRESP);
|
||||
n = res_send(qbuf, n, abuf, MAX_HESRESP);
|
||||
if (n < 0) {
|
||||
__set_errno(ECONNREFUSED);
|
||||
return (NULL);
|
||||
@@ -421,7 +411,7 @@ get_txt_records(struct hesiod_p *ctx, int class, const char *name) {
|
||||
cp += INT16SZ + INT32SZ; /* skip the ttl, too */
|
||||
rr.dlen = ns_get16(cp);
|
||||
cp += INT16SZ;
|
||||
if (cp + rr.dlen > eom) {
|
||||
if (rr.dlen == 0 || cp + rr.dlen > eom) {
|
||||
__set_errno(EMSGSIZE);
|
||||
goto cleanup;
|
||||
}
|
||||
@@ -464,44 +454,3 @@ get_txt_records(struct hesiod_p *ctx, int class, const char *name) {
|
||||
free(list);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
struct __res_state *
|
||||
__hesiod_res_get(void *context) {
|
||||
struct hesiod_p *ctx = context;
|
||||
|
||||
if (!ctx->res) {
|
||||
struct __res_state *res;
|
||||
res = (struct __res_state *)calloc(1, sizeof *res);
|
||||
if (res == NULL)
|
||||
return (NULL);
|
||||
__hesiod_res_set(ctx, res, free);
|
||||
}
|
||||
|
||||
return (ctx->res);
|
||||
}
|
||||
|
||||
void
|
||||
__hesiod_res_set(void *context, struct __res_state *res,
|
||||
void (*free_res)(void *)) {
|
||||
struct hesiod_p *ctx = context;
|
||||
|
||||
if (ctx->res && ctx->free_res) {
|
||||
res_nclose(ctx->res);
|
||||
(*ctx->free_res)(ctx->res);
|
||||
}
|
||||
|
||||
ctx->res = res;
|
||||
ctx->free_res = free_res;
|
||||
}
|
||||
|
||||
static int
|
||||
init(struct hesiod_p *ctx) {
|
||||
|
||||
if (!ctx->res && !__hesiod_res_get(ctx))
|
||||
return (-1);
|
||||
|
||||
if (__res_maybe_init (ctx->res, 0) == -1)
|
||||
return (-1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
+22
-12
@@ -1,3 +1,20 @@
|
||||
/* Copyright (C) 1997-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) 1996,1999 by Internet Software Consortium.
|
||||
*
|
||||
@@ -19,22 +36,15 @@
|
||||
* This file is primarily maintained by <tytso@mit.edu> and <ghudson@mit.edu>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $BINDId: hesiod.h,v 1.7 1999/01/08 19:22:45 vixie Exp $
|
||||
*/
|
||||
|
||||
#ifndef _HESIOD_H_INCLUDED
|
||||
#define _HESIOD_H_INCLUDED
|
||||
|
||||
int hesiod_init (void **context);
|
||||
void hesiod_end (void *context);
|
||||
int hesiod_init (void **context) attribute_hidden;
|
||||
void hesiod_end (void *context) attribute_hidden;
|
||||
char * hesiod_to_bind (void *context, const char *name,
|
||||
const char *type);
|
||||
const char *type) attribute_hidden;
|
||||
char ** hesiod_resolve (void *context, const char *name,
|
||||
const char *type);
|
||||
void hesiod_free_list (void *context, char **list);
|
||||
struct __res_state * __hesiod_res_get (void *context);
|
||||
void __hesiod_res_set (void *context, struct __res_state *,
|
||||
void (*)(void *));
|
||||
const char *type) attribute_hidden;
|
||||
void hesiod_free_list (void *context, char **list) attribute_hidden;
|
||||
|
||||
#endif /*_HESIOD_H_INCLUDED*/
|
||||
|
||||
+17
-9
@@ -1,3 +1,20 @@
|
||||
/* Copyright (C) 1997-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) 1996,1999 by Internet Software Consortium.
|
||||
*
|
||||
@@ -19,10 +36,6 @@
|
||||
* This file is primarily maintained by <tytso@mit.edu> and <ghudson@mit.edu>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $BINDId: hesiod_p.h,v 1.9 1999/01/08 19:24:39 vixie Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* hesiod_p.h -- private definitions for the hesiod library
|
||||
*/
|
||||
@@ -36,11 +49,6 @@
|
||||
struct hesiod_p {
|
||||
char * LHS; /* normally ".ns" */
|
||||
char * RHS; /* AKA the default hesiod domain */
|
||||
struct __res_state * res; /* resolver context */
|
||||
void (*free_res)(void *);
|
||||
void (*res_set)(struct hesiod_p *, struct __res_state *,
|
||||
void (*)(void *));
|
||||
struct __res_state * (*res_get)(struct hesiod_p *);
|
||||
int classes[2]; /* The class search order. */
|
||||
};
|
||||
|
||||
|
||||
@@ -26,8 +26,6 @@
|
||||
#include <string.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#include "nss_hesiod.h"
|
||||
|
||||
/* Get the declaration of the parser function. */
|
||||
#define ENTNAME grent
|
||||
#define STRUCTURE group
|
||||
@@ -58,8 +56,7 @@ lookup (const char *name, const char *type, struct group *grp,
|
||||
size_t len;
|
||||
int olderr = errno;
|
||||
|
||||
context = _nss_hesiod_init ();
|
||||
if (context == NULL)
|
||||
if (hesiod_init (&context) < 0)
|
||||
return NSS_STATUS_UNAVAIL;
|
||||
|
||||
list = hesiod_resolve (context, name, type);
|
||||
@@ -179,8 +176,7 @@ _nss_hesiod_initgroups_dyn (const char *user, gid_t group, long int *start,
|
||||
gid_t *groups = *groupsp;
|
||||
int save_errno;
|
||||
|
||||
context = _nss_hesiod_init ();
|
||||
if (context == NULL)
|
||||
if (hesiod_init (&context) < 0)
|
||||
return NSS_STATUS_UNAVAIL;
|
||||
|
||||
list = hesiod_resolve (context, user, "grplist");
|
||||
|
||||
@@ -25,8 +25,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "nss_hesiod.h"
|
||||
|
||||
/* Declare a parser for Hesiod protocol entries. Although the format
|
||||
of the entries is identical to those in /etc/protocols, here is no
|
||||
predefined parser for us to use. */
|
||||
@@ -68,8 +66,7 @@ lookup (const char *name, const char *type, struct protoent *proto,
|
||||
int found;
|
||||
int olderr = errno;
|
||||
|
||||
context = _nss_hesiod_init ();
|
||||
if (context == NULL)
|
||||
if (hesiod_init (&context) < 0)
|
||||
return NSS_STATUS_UNAVAIL;
|
||||
|
||||
list = hesiod_resolve (context, name, type);
|
||||
|
||||
@@ -24,8 +24,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "nss_hesiod.h"
|
||||
|
||||
/* Get the declaration of the parser function. */
|
||||
#define ENTNAME pwent
|
||||
#define STRUCTURE passwd
|
||||
@@ -56,8 +54,7 @@ lookup (const char *name, const char *type, struct passwd *pwd,
|
||||
size_t len;
|
||||
int olderr = errno;
|
||||
|
||||
context = _nss_hesiod_init ();
|
||||
if (context == NULL)
|
||||
if (hesiod_init (&context) < 0)
|
||||
return NSS_STATUS_UNAVAIL;
|
||||
|
||||
list = hesiod_resolve (context, name, type);
|
||||
|
||||
@@ -25,8 +25,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "nss_hesiod.h"
|
||||
|
||||
/* Hesiod uses a format for service entries that differs from the
|
||||
traditional format. We therefore declare our own parser. */
|
||||
|
||||
@@ -69,8 +67,7 @@ lookup (const char *name, const char *type, const char *protocol,
|
||||
int found;
|
||||
int olderr = errno;
|
||||
|
||||
context = _nss_hesiod_init ();
|
||||
if (context == NULL)
|
||||
if (hesiod_init (&context) < 0)
|
||||
return NSS_STATUS_UNAVAIL;
|
||||
|
||||
list = hesiod_resolve (context, name, type);
|
||||
|
||||
@@ -121,6 +121,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__ */
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef _PRINTF_H
|
||||
|
||||
#include <stdio-common/printf.h>
|
||||
#include <xlocale.h>
|
||||
|
||||
/* Now define the internal interfaces. */
|
||||
extern int __printf_fphex (FILE *, const struct printf_info *,
|
||||
@@ -8,5 +9,8 @@ extern int __printf_fphex (FILE *, const struct printf_info *,
|
||||
extern int __printf_fp (FILE *, const struct printf_info *,
|
||||
const void *const *);
|
||||
libc_hidden_proto (__printf_fp)
|
||||
extern int __printf_fp_l (FILE *, locale_t, const struct printf_info *,
|
||||
const void *const *);
|
||||
libc_hidden_proto (__printf_fp_l)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
#include <misc/sys/auxv.h>
|
||||
+3
-1
@@ -50,7 +50,7 @@ aux := check_pf check_native ifreq
|
||||
|
||||
tests := htontest test_ifindex tst-ntoa tst-ether_aton tst-network \
|
||||
tst-gethnm test-ifaddrs bug-if1 test-inet6_opt tst-ether_line \
|
||||
tst-getni1 tst-getni2 tst-inet6_rth tst-checks
|
||||
tst-getni1 tst-getni2 tst-inet6_rth tst-checks tst-sockaddr
|
||||
|
||||
include ../Rules
|
||||
|
||||
@@ -84,6 +84,8 @@ CFLAGS-either_hton.c = -fexceptions
|
||||
CFLAGS-getnetgrent.c = -fexceptions
|
||||
CFLAGS-getnetgrent_r.c = -fexceptions
|
||||
|
||||
CFLAGS-tst-sockaddr.c = -fno-strict-aliasing
|
||||
|
||||
endif
|
||||
|
||||
ifeq ($(build-static-nss),yes)
|
||||
|
||||
+346
-252
@@ -1,3 +1,21 @@
|
||||
/* Convert socket address to string using Name Service Switch modules.
|
||||
Copyright (C) 1997-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/>. */
|
||||
|
||||
/* The Inner Net License, Version 2.00
|
||||
|
||||
The author(s) grant permission for redistribution and use in source and
|
||||
@@ -169,20 +187,322 @@ nrl_domainname (void)
|
||||
return domain;
|
||||
};
|
||||
|
||||
/* Copy a string to a destination buffer with length checking. Return
|
||||
EAI_OVERFLOW if the buffer is not large enough, and 0 on
|
||||
success. */
|
||||
static int
|
||||
checked_copy (char *dest, size_t destlen, const char *source)
|
||||
{
|
||||
size_t source_length = strlen (source);
|
||||
if (source_length + 1 > destlen)
|
||||
return EAI_OVERFLOW;
|
||||
memcpy (dest, source, source_length + 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Helper function for CHECKED_SNPRINTF below. */
|
||||
static int
|
||||
check_sprintf_result (int result, size_t destlen)
|
||||
{
|
||||
if (result < 0)
|
||||
return EAI_SYSTEM;
|
||||
if ((size_t) result >= destlen)
|
||||
/* If ret == destlen, there was no room for the terminating NUL
|
||||
character. */
|
||||
return EAI_OVERFLOW;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Format a string in the destination buffer. Return 0 on success,
|
||||
EAI_OVERFLOW in case the buffer is too small, or EAI_SYSTEM on any
|
||||
other error. */
|
||||
#define CHECKED_SNPRINTF(dest, destlen, format, ...) \
|
||||
check_sprintf_result \
|
||||
(__snprintf (dest, destlen, format, __VA_ARGS__), destlen)
|
||||
|
||||
/* Convert host name, AF_INET/AF_INET6 case, name only. */
|
||||
static int
|
||||
gni_host_inet_name (struct scratch_buffer *tmpbuf,
|
||||
const struct sockaddr *sa, socklen_t addrlen,
|
||||
char *host, socklen_t hostlen, int flags)
|
||||
{
|
||||
int herrno;
|
||||
struct hostent th;
|
||||
struct hostent *h = NULL;
|
||||
if (sa->sa_family == AF_INET6)
|
||||
{
|
||||
const struct sockaddr_in6 *sin6p = (const struct sockaddr_in6 *) sa;
|
||||
while (__gethostbyaddr_r (&sin6p->sin6_addr, sizeof(struct in6_addr),
|
||||
AF_INET6, &th, tmpbuf->data, tmpbuf->length,
|
||||
&h, &herrno))
|
||||
if (herrno == NETDB_INTERNAL && errno == ERANGE)
|
||||
{
|
||||
if (!scratch_buffer_grow (tmpbuf))
|
||||
{
|
||||
__set_h_errno (herrno);
|
||||
return EAI_MEMORY;
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
const struct sockaddr_in *sinp = (const struct sockaddr_in *) sa;
|
||||
while (__gethostbyaddr_r (&sinp->sin_addr, sizeof(struct in_addr),
|
||||
AF_INET, &th, tmpbuf->data, tmpbuf->length,
|
||||
&h, &herrno))
|
||||
if (herrno == NETDB_INTERNAL && errno == ERANGE)
|
||||
{
|
||||
if (!scratch_buffer_grow (tmpbuf))
|
||||
{
|
||||
__set_h_errno (herrno);
|
||||
return EAI_MEMORY;
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (h == NULL)
|
||||
{
|
||||
if (herrno == NETDB_INTERNAL)
|
||||
{
|
||||
__set_h_errno (herrno);
|
||||
return EAI_SYSTEM;
|
||||
}
|
||||
if (herrno == TRY_AGAIN)
|
||||
{
|
||||
__set_h_errno (herrno);
|
||||
return EAI_AGAIN;
|
||||
}
|
||||
}
|
||||
|
||||
if (h)
|
||||
{
|
||||
char *c;
|
||||
if ((flags & NI_NOFQDN)
|
||||
&& (c = nrl_domainname ())
|
||||
&& (c = strstr (h->h_name, c))
|
||||
&& (c != h->h_name) && (*(--c) == '.'))
|
||||
/* Terminate the string after the prefix. */
|
||||
*c = '\0';
|
||||
|
||||
#ifdef HAVE_LIBIDN
|
||||
/* If requested, convert from the IDN format. */
|
||||
if (flags & NI_IDN)
|
||||
{
|
||||
int idn_flags = 0;
|
||||
if (flags & NI_IDN_ALLOW_UNASSIGNED)
|
||||
idn_flags |= IDNA_ALLOW_UNASSIGNED;
|
||||
if (flags & NI_IDN_USE_STD3_ASCII_RULES)
|
||||
idn_flags |= IDNA_USE_STD3_ASCII_RULES;
|
||||
|
||||
char *out;
|
||||
int rc = __idna_to_unicode_lzlz (h->h_name, &out,
|
||||
idn_flags);
|
||||
if (rc != IDNA_SUCCESS)
|
||||
{
|
||||
if (rc == IDNA_MALLOC_ERROR)
|
||||
return EAI_MEMORY;
|
||||
if (rc == IDNA_DLOPEN_ERROR)
|
||||
return EAI_SYSTEM;
|
||||
return EAI_IDN_ENCODE;
|
||||
}
|
||||
|
||||
if (out != h->h_name)
|
||||
{
|
||||
h->h_name = strdupa (out);
|
||||
free (out);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t len = strlen (h->h_name) + 1;
|
||||
if (len > hostlen)
|
||||
return EAI_OVERFLOW;
|
||||
|
||||
memcpy (host, h->h_name, len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return EAI_NONAME;
|
||||
}
|
||||
|
||||
/* Convert host name, AF_INET/AF_INET6 case, numeric conversion. */
|
||||
static int
|
||||
gni_host_inet_numeric (struct scratch_buffer *tmpbuf,
|
||||
const struct sockaddr *sa, socklen_t addrlen,
|
||||
char *host, socklen_t hostlen, int flags)
|
||||
{
|
||||
if (sa->sa_family == AF_INET6)
|
||||
{
|
||||
const struct sockaddr_in6 *sin6p = (const struct sockaddr_in6 *) sa;
|
||||
if (inet_ntop (AF_INET6, &sin6p->sin6_addr, host, hostlen) == NULL)
|
||||
return EAI_OVERFLOW;
|
||||
|
||||
uint32_t scopeid = sin6p->sin6_scope_id;
|
||||
if (scopeid != 0)
|
||||
{
|
||||
size_t used_hostlen = __strnlen (host, hostlen);
|
||||
/* Location of the scope string in the host buffer. */
|
||||
char *scope_start = host + used_hostlen;
|
||||
size_t scope_length = hostlen - used_hostlen;
|
||||
|
||||
if (IN6_IS_ADDR_LINKLOCAL (&sin6p->sin6_addr)
|
||||
|| IN6_IS_ADDR_MC_LINKLOCAL (&sin6p->sin6_addr))
|
||||
{
|
||||
char scopebuf[IFNAMSIZ];
|
||||
if (if_indextoname (scopeid, scopebuf) != NULL)
|
||||
return CHECKED_SNPRINTF
|
||||
(scope_start, scope_length,
|
||||
"%c%s", SCOPE_DELIMITER, scopebuf);
|
||||
}
|
||||
return CHECKED_SNPRINTF
|
||||
(scope_start, scope_length, "%c%u", SCOPE_DELIMITER, scopeid);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const struct sockaddr_in *sinp = (const struct sockaddr_in *) sa;
|
||||
if (inet_ntop (AF_INET, &sinp->sin_addr, host, hostlen) == NULL)
|
||||
return EAI_OVERFLOW;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Convert AF_INET or AF_INET6 socket address, host part. */
|
||||
static int
|
||||
gni_host_inet (struct scratch_buffer *tmpbuf,
|
||||
const struct sockaddr *sa, socklen_t addrlen,
|
||||
char *host, socklen_t hostlen, int flags)
|
||||
{
|
||||
if (!(flags & NI_NUMERICHOST))
|
||||
{
|
||||
int result = gni_host_inet_name
|
||||
(tmpbuf, sa, addrlen, host, hostlen, flags);
|
||||
if (result != EAI_NONAME)
|
||||
return result;
|
||||
}
|
||||
|
||||
if (flags & NI_NAMEREQD)
|
||||
return EAI_NONAME;
|
||||
else
|
||||
return gni_host_inet_numeric
|
||||
(tmpbuf, sa, addrlen, host, hostlen, flags);
|
||||
}
|
||||
|
||||
/* Convert AF_LOCAL socket address, host part. */
|
||||
static int
|
||||
gni_host_local (struct scratch_buffer *tmpbuf,
|
||||
const struct sockaddr *sa, socklen_t addrlen,
|
||||
char *host, socklen_t hostlen, int flags)
|
||||
{
|
||||
if (!(flags & NI_NUMERICHOST))
|
||||
{
|
||||
struct utsname utsname;
|
||||
if (uname (&utsname) == 0)
|
||||
return checked_copy (host, hostlen, utsname.nodename);
|
||||
}
|
||||
|
||||
if (flags & NI_NAMEREQD)
|
||||
return EAI_NONAME;
|
||||
|
||||
return checked_copy (host, hostlen, "localhost");
|
||||
}
|
||||
|
||||
/* Convert the host part of an AF_LOCAK socket address. */
|
||||
static int
|
||||
gni_host (struct scratch_buffer *tmpbuf,
|
||||
const struct sockaddr *sa, socklen_t addrlen,
|
||||
char *host, socklen_t hostlen, int flags)
|
||||
{
|
||||
switch (sa->sa_family)
|
||||
{
|
||||
case AF_INET:
|
||||
case AF_INET6:
|
||||
return gni_host_inet (tmpbuf, sa, addrlen, host, hostlen, flags);
|
||||
|
||||
case AF_LOCAL:
|
||||
return gni_host_local (tmpbuf, sa, addrlen, host, hostlen, flags);
|
||||
|
||||
default:
|
||||
return EAI_FAMILY;
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert service to string, AF_INET and AF_INET6 variant. */
|
||||
static int
|
||||
gni_serv_inet (struct scratch_buffer *tmpbuf,
|
||||
const struct sockaddr *sa, socklen_t addrlen,
|
||||
char *serv, socklen_t servlen, int flags)
|
||||
{
|
||||
_Static_assert
|
||||
(offsetof (struct sockaddr_in, sin_port)
|
||||
== offsetof (struct sockaddr_in6, sin6_port)
|
||||
&& sizeof (((struct sockaddr_in) {}).sin_port) == sizeof (in_port_t)
|
||||
&& sizeof (((struct sockaddr_in6) {}).sin6_port) == sizeof (in_port_t),
|
||||
"AF_INET and AF_INET6 port consistency");
|
||||
const struct sockaddr_in *sinp = (const struct sockaddr_in *) sa;
|
||||
if (!(flags & NI_NUMERICSERV))
|
||||
{
|
||||
struct servent *s, ts;
|
||||
int e;
|
||||
while ((e = __getservbyport_r (sinp->sin_port,
|
||||
((flags & NI_DGRAM)
|
||||
? "udp" : "tcp"), &ts,
|
||||
tmpbuf->data, tmpbuf->length, &s)))
|
||||
{
|
||||
if (e == ERANGE)
|
||||
{
|
||||
if (!scratch_buffer_grow (tmpbuf))
|
||||
return EAI_MEMORY;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (s)
|
||||
return checked_copy (serv, servlen, s->s_name);
|
||||
/* Fall through to numeric conversion. */
|
||||
}
|
||||
return CHECKED_SNPRINTF (serv, servlen, "%d", ntohs (sinp->sin_port));
|
||||
}
|
||||
|
||||
/* Convert service to string, AF_LOCAL variant. */
|
||||
static int
|
||||
gni_serv_local (struct scratch_buffer *tmpbuf,
|
||||
const struct sockaddr *sa, socklen_t addrlen,
|
||||
char *serv, socklen_t servlen, int flags)
|
||||
{
|
||||
return checked_copy
|
||||
(serv, servlen, ((const struct sockaddr_un *) sa)->sun_path);
|
||||
}
|
||||
|
||||
/* Convert service to string, dispatching to the implementations
|
||||
above. */
|
||||
static int
|
||||
gni_serv (struct scratch_buffer *tmpbuf,
|
||||
const struct sockaddr *sa, socklen_t addrlen,
|
||||
char *serv, socklen_t servlen, int flags)
|
||||
{
|
||||
switch (sa->sa_family)
|
||||
{
|
||||
case AF_INET:
|
||||
case AF_INET6:
|
||||
return gni_serv_inet (tmpbuf, sa, addrlen, serv, servlen, flags);
|
||||
case AF_LOCAL:
|
||||
return gni_serv_local (tmpbuf, sa, addrlen, serv, servlen, flags);
|
||||
default:
|
||||
return EAI_FAMILY;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host,
|
||||
socklen_t hostlen, char *serv, socklen_t servlen,
|
||||
int flags)
|
||||
{
|
||||
int serrno = errno;
|
||||
int herrno;
|
||||
struct hostent th;
|
||||
int ok = 0;
|
||||
struct scratch_buffer tmpbuf;
|
||||
|
||||
scratch_buffer_init (&tmpbuf);
|
||||
|
||||
if (flags & ~(NI_NUMERICHOST|NI_NUMERICSERV|NI_NOFQDN|NI_NAMEREQD|NI_DGRAM
|
||||
#ifdef HAVE_LIBIDN
|
||||
|NI_IDN|NI_IDN_ALLOW_UNASSIGNED|NI_IDN_USE_STD3_ASCII_RULES
|
||||
@@ -214,256 +534,30 @@ getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host,
|
||||
return EAI_FAMILY;
|
||||
}
|
||||
|
||||
struct scratch_buffer tmpbuf;
|
||||
scratch_buffer_init (&tmpbuf);
|
||||
|
||||
if (host != NULL && hostlen > 0)
|
||||
switch (sa->sa_family)
|
||||
{
|
||||
case AF_INET:
|
||||
case AF_INET6:
|
||||
if (!(flags & NI_NUMERICHOST))
|
||||
{
|
||||
struct hostent *h = NULL;
|
||||
if (sa->sa_family == AF_INET6)
|
||||
{
|
||||
while (__gethostbyaddr_r ((const void *) &(((const struct sockaddr_in6 *) sa)->sin6_addr),
|
||||
sizeof(struct in6_addr),
|
||||
AF_INET6, &th,
|
||||
tmpbuf.data, tmpbuf.length,
|
||||
&h, &herrno))
|
||||
if (herrno == NETDB_INTERNAL && errno == ERANGE)
|
||||
{
|
||||
if (!scratch_buffer_grow (&tmpbuf))
|
||||
{
|
||||
__set_h_errno (herrno);
|
||||
return EAI_MEMORY;
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (__gethostbyaddr_r ((const void *) &(((const struct sockaddr_in *)sa)->sin_addr),
|
||||
sizeof(struct in_addr),
|
||||
AF_INET, &th,
|
||||
tmpbuf.data, tmpbuf.length,
|
||||
&h, &herrno))
|
||||
if (herrno == NETDB_INTERNAL && errno == ERANGE)
|
||||
{
|
||||
if (!scratch_buffer_grow (&tmpbuf))
|
||||
{
|
||||
__set_h_errno (herrno);
|
||||
return EAI_MEMORY;
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (h == NULL)
|
||||
{
|
||||
if (herrno == NETDB_INTERNAL)
|
||||
{
|
||||
__set_h_errno (herrno);
|
||||
return EAI_SYSTEM;
|
||||
}
|
||||
if (herrno == TRY_AGAIN)
|
||||
{
|
||||
__set_h_errno (herrno);
|
||||
return EAI_AGAIN;
|
||||
}
|
||||
}
|
||||
|
||||
if (h)
|
||||
{
|
||||
char *c;
|
||||
if ((flags & NI_NOFQDN)
|
||||
&& (c = nrl_domainname ())
|
||||
&& (c = strstr (h->h_name, c))
|
||||
&& (c != h->h_name) && (*(--c) == '.'))
|
||||
/* Terminate the string after the prefix. */
|
||||
*c = '\0';
|
||||
|
||||
#ifdef HAVE_LIBIDN
|
||||
/* If requested, convert from the IDN format. */
|
||||
if (flags & NI_IDN)
|
||||
{
|
||||
int idn_flags = 0;
|
||||
if (flags & NI_IDN_ALLOW_UNASSIGNED)
|
||||
idn_flags |= IDNA_ALLOW_UNASSIGNED;
|
||||
if (flags & NI_IDN_USE_STD3_ASCII_RULES)
|
||||
idn_flags |= IDNA_USE_STD3_ASCII_RULES;
|
||||
|
||||
char *out;
|
||||
int rc = __idna_to_unicode_lzlz (h->h_name, &out,
|
||||
idn_flags);
|
||||
if (rc != IDNA_SUCCESS)
|
||||
{
|
||||
if (rc == IDNA_MALLOC_ERROR)
|
||||
return EAI_MEMORY;
|
||||
if (rc == IDNA_DLOPEN_ERROR)
|
||||
return EAI_SYSTEM;
|
||||
return EAI_IDN_ENCODE;
|
||||
}
|
||||
|
||||
if (out != h->h_name)
|
||||
{
|
||||
h->h_name = strdupa (out);
|
||||
free (out);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t len = strlen (h->h_name) + 1;
|
||||
if (len > hostlen)
|
||||
return EAI_OVERFLOW;
|
||||
|
||||
memcpy (host, h->h_name, len);
|
||||
|
||||
ok = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
if (flags & NI_NAMEREQD)
|
||||
{
|
||||
__set_errno (serrno);
|
||||
return EAI_NONAME;
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *c;
|
||||
if (sa->sa_family == AF_INET6)
|
||||
{
|
||||
const struct sockaddr_in6 *sin6p;
|
||||
uint32_t scopeid;
|
||||
|
||||
sin6p = (const struct sockaddr_in6 *) sa;
|
||||
|
||||
c = inet_ntop (AF_INET6,
|
||||
(const void *) &sin6p->sin6_addr, host, hostlen);
|
||||
scopeid = sin6p->sin6_scope_id;
|
||||
if (scopeid != 0)
|
||||
{
|
||||
/* Buffer is >= IFNAMSIZ+1. */
|
||||
char scopebuf[IFNAMSIZ + 1];
|
||||
char *scopeptr;
|
||||
int ni_numericscope = 0;
|
||||
size_t real_hostlen = __strnlen (host, hostlen);
|
||||
size_t scopelen = 0;
|
||||
|
||||
scopebuf[0] = SCOPE_DELIMITER;
|
||||
scopebuf[1] = '\0';
|
||||
scopeptr = &scopebuf[1];
|
||||
|
||||
if (IN6_IS_ADDR_LINKLOCAL (&sin6p->sin6_addr)
|
||||
|| IN6_IS_ADDR_MC_LINKLOCAL (&sin6p->sin6_addr))
|
||||
{
|
||||
if (if_indextoname (scopeid, scopeptr) == NULL)
|
||||
++ni_numericscope;
|
||||
else
|
||||
scopelen = strlen (scopebuf);
|
||||
}
|
||||
else
|
||||
++ni_numericscope;
|
||||
|
||||
if (ni_numericscope)
|
||||
scopelen = 1 + __snprintf (scopeptr,
|
||||
(scopebuf
|
||||
+ sizeof scopebuf
|
||||
- scopeptr),
|
||||
"%u", scopeid);
|
||||
|
||||
if (real_hostlen + scopelen + 1 > hostlen)
|
||||
/* Signal the buffer is too small. This is
|
||||
what inet_ntop does. */
|
||||
c = NULL;
|
||||
else
|
||||
memcpy (host + real_hostlen, scopebuf, scopelen + 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
c = inet_ntop (AF_INET,
|
||||
(const void *) &(((const struct sockaddr_in *) sa)->sin_addr),
|
||||
host, hostlen);
|
||||
if (c == NULL)
|
||||
return EAI_OVERFLOW;
|
||||
}
|
||||
ok = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case AF_LOCAL:
|
||||
if (!(flags & NI_NUMERICHOST))
|
||||
{
|
||||
struct utsname utsname;
|
||||
|
||||
if (!uname (&utsname))
|
||||
{
|
||||
strncpy (host, utsname.nodename, hostlen);
|
||||
break;
|
||||
};
|
||||
};
|
||||
|
||||
if (flags & NI_NAMEREQD)
|
||||
{
|
||||
__set_errno (serrno);
|
||||
return EAI_NONAME;
|
||||
}
|
||||
|
||||
strncpy (host, "localhost", hostlen);
|
||||
break;
|
||||
|
||||
default:
|
||||
return EAI_FAMILY;
|
||||
{
|
||||
int result = gni_host (&tmpbuf, sa, addrlen, host, hostlen, flags);
|
||||
if (result != 0)
|
||||
{
|
||||
scratch_buffer_free (&tmpbuf);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (serv && (servlen > 0))
|
||||
switch (sa->sa_family)
|
||||
{
|
||||
case AF_INET:
|
||||
case AF_INET6:
|
||||
if (!(flags & NI_NUMERICSERV))
|
||||
{
|
||||
struct servent *s, ts;
|
||||
int e;
|
||||
while ((e = __getservbyport_r (((const struct sockaddr_in *) sa)->sin_port,
|
||||
((flags & NI_DGRAM)
|
||||
? "udp" : "tcp"), &ts,
|
||||
tmpbuf.data, tmpbuf.length, &s)))
|
||||
{
|
||||
if (e == ERANGE)
|
||||
{
|
||||
if (!scratch_buffer_grow (&tmpbuf))
|
||||
return EAI_MEMORY;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (s)
|
||||
{
|
||||
strncpy (serv, s->s_name, servlen);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (__snprintf (serv, servlen, "%d",
|
||||
ntohs (((const struct sockaddr_in *) sa)->sin_port))
|
||||
+ 1 > servlen)
|
||||
return EAI_OVERFLOW;
|
||||
|
||||
break;
|
||||
|
||||
case AF_LOCAL:
|
||||
strncpy (serv, ((const struct sockaddr_un *) sa)->sun_path, servlen);
|
||||
break;
|
||||
{
|
||||
int result = gni_serv (&tmpbuf, sa, addrlen, serv, servlen, flags);
|
||||
if (result != 0)
|
||||
{
|
||||
scratch_buffer_free (&tmpbuf);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (host && (hostlen > 0))
|
||||
host[hostlen-1] = 0;
|
||||
if (serv && (servlen > 0))
|
||||
serv[servlen-1] = 0;
|
||||
errno = serrno;
|
||||
scratch_buffer_free (&tmpbuf);
|
||||
return 0;
|
||||
}
|
||||
libc_hidden_def (getnameinfo)
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
/* Tests for socket address type definitions.
|
||||
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 <netinet/in.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
/* This is a copy of the previous definition of struct
|
||||
sockaddr_storage. It is not equal to the old value of _SS_SIZE
|
||||
(128) on all architectures. We must stay compatible with the old
|
||||
definition. */
|
||||
|
||||
#define OLD_REFERENCE_SIZE 128
|
||||
#define OLD_PADSIZE (OLD_REFERENCE_SIZE - (2 * sizeof (__ss_aligntype)))
|
||||
struct sockaddr_storage_old
|
||||
{
|
||||
__SOCKADDR_COMMON (old_);
|
||||
__ss_aligntype old_align;
|
||||
char old_padding[OLD_PADSIZE];
|
||||
};
|
||||
|
||||
static bool errors;
|
||||
|
||||
static void
|
||||
check (bool ok, const char *message)
|
||||
{
|
||||
if (!ok)
|
||||
{
|
||||
printf ("error: failed check: %s\n", message);
|
||||
errors = true;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
check (OLD_REFERENCE_SIZE >= _SS_SIZE,
|
||||
"old target size is not smaller than actual size");
|
||||
check (sizeof (struct sockaddr_storage_old)
|
||||
== sizeof (struct sockaddr_storage),
|
||||
"old and new sizes match");
|
||||
check (__alignof (struct sockaddr_storage_old)
|
||||
== __alignof (struct sockaddr_storage),
|
||||
"old and new alignment matches");
|
||||
check (offsetof (struct sockaddr_storage_old, old_family)
|
||||
== offsetof (struct sockaddr_storage, ss_family),
|
||||
"old and new family offsets match");
|
||||
check (sizeof (struct sockaddr_storage) == _SS_SIZE,
|
||||
"struct sockaddr_storage size");
|
||||
|
||||
/* Check for lack of holes in the struct definition. */
|
||||
check (offsetof (struct sockaddr_storage, __ss_padding)
|
||||
== __SOCKADDR_COMMON_SIZE,
|
||||
"implicit padding before explicit padding");
|
||||
check (offsetof (struct sockaddr_storage, __ss_align)
|
||||
== __SOCKADDR_COMMON_SIZE
|
||||
+ sizeof (((struct sockaddr_storage) {}).__ss_padding),
|
||||
"implicit padding before explicit padding");
|
||||
|
||||
/* Check for POSIX compatibility requirements between struct
|
||||
sockaddr_storage and struct sockaddr_un. */
|
||||
check (sizeof (struct sockaddr_storage) >= sizeof (struct sockaddr_un),
|
||||
"sockaddr_storage is at least as large as sockaddr_un");
|
||||
check (__alignof (struct sockaddr_storage)
|
||||
>= __alignof (struct sockaddr_un),
|
||||
"sockaddr_storage is at least as aligned as sockaddr_un");
|
||||
check (offsetof (struct sockaddr_storage, ss_family)
|
||||
== offsetof (struct sockaddr_un, sun_family),
|
||||
"family offsets match");
|
||||
|
||||
/* Check that the compiler preserves bit patterns in aggregate
|
||||
copies. Based on <https://gcc.gnu.org/PR71120>. */
|
||||
check (sizeof (struct sockaddr_storage) >= sizeof (struct sockaddr_in),
|
||||
"sockaddr_storage is at least as large as sockaddr_in");
|
||||
{
|
||||
struct sockaddr_storage addr;
|
||||
memset (&addr, 0, sizeof (addr));
|
||||
{
|
||||
struct sockaddr_in *sinp = (struct sockaddr_in *)&addr;
|
||||
sinp->sin_family = AF_INET;
|
||||
sinp->sin_addr.s_addr = htonl (INADDR_LOOPBACK);
|
||||
sinp->sin_port = htons (80);
|
||||
}
|
||||
struct sockaddr_storage copy;
|
||||
copy = addr;
|
||||
|
||||
struct sockaddr_storage *p = malloc (sizeof (*p));
|
||||
if (p == NULL)
|
||||
{
|
||||
printf ("error: malloc: %m\n");
|
||||
return 1;
|
||||
}
|
||||
*p = copy;
|
||||
const struct sockaddr_in *sinp = (const struct sockaddr_in *)p;
|
||||
check (sinp->sin_family == AF_INET, "sin_family");
|
||||
check (sinp->sin_addr.s_addr == htonl (INADDR_LOOPBACK), "sin_addr");
|
||||
check (sinp->sin_port == htons (80), "sin_port");
|
||||
free (p);
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
#define TEST_FUNCTION do_test ()
|
||||
#include "../test-skeleton.c"
|
||||
@@ -193,7 +193,7 @@ FTS *__REDIRECT (fts_open, (char * const *, int,
|
||||
int (*)(const FTSENT **, const FTSENT **)),
|
||||
fts64_open);
|
||||
FTSENT *__REDIRECT (fts_read, (FTS *), fts64_read);
|
||||
int __REDIRECT (fts_set, (FTS *, FTSENT *, int), fts64_set) __THROW;
|
||||
int __REDIRECT_NTH (fts_set, (FTS *, FTSENT *, int), fts64_set);
|
||||
# else
|
||||
# define fts_children fts64_children
|
||||
# define fts_close fts64_close
|
||||
|
||||
+17
-15
@@ -50,16 +50,14 @@ fmemopen_read (void *cookie, char *b, size_t s)
|
||||
|
||||
if (c->pos + s > c->maxpos)
|
||||
{
|
||||
if ((size_t) c->pos == c->maxpos)
|
||||
return 0;
|
||||
s = c->size - c->pos;
|
||||
s = c->maxpos - c->pos;
|
||||
if ((size_t) c->pos > c->maxpos)
|
||||
s = 0;
|
||||
}
|
||||
|
||||
memcpy (b, &(c->buffer[c->pos]), s);
|
||||
|
||||
c->pos += s;
|
||||
if ((size_t) c->pos > c->maxpos)
|
||||
c->maxpos = c->pos;
|
||||
|
||||
return s;
|
||||
}
|
||||
@@ -70,28 +68,29 @@ fmemopen_write (void *cookie, const char *b, size_t s)
|
||||
{
|
||||
fmemopen_cookie_t *c = (fmemopen_cookie_t *) cookie;;
|
||||
_IO_off64_t pos = c->append ? c->maxpos : c->pos;
|
||||
int addnullc;
|
||||
int addnullc = (s == 0 || b[s - 1] != '\0');
|
||||
|
||||
addnullc = (s == 0 || b[s - 1] != '\0');
|
||||
|
||||
if (pos + s + addnullc > c->size)
|
||||
if (pos + s > c->size)
|
||||
{
|
||||
if ((size_t) (c->pos + addnullc) >= c->size)
|
||||
{
|
||||
__set_errno (ENOSPC);
|
||||
return 0;
|
||||
}
|
||||
s = c->size - pos - addnullc;
|
||||
s = c->size - pos;
|
||||
}
|
||||
|
||||
memcpy (&(c->buffer[pos]), b, s);
|
||||
|
||||
pos += s;
|
||||
if ((size_t) pos > c->maxpos)
|
||||
c->pos = pos + s;
|
||||
if ((size_t) c->pos > c->maxpos)
|
||||
{
|
||||
c->maxpos = pos;
|
||||
if (addnullc)
|
||||
c->maxpos = c->pos;
|
||||
if (c->maxpos < c->size && addnullc)
|
||||
c->buffer[c->maxpos] = '\0';
|
||||
/* A null byte is written in a stream open for update iff it fits. */
|
||||
else if (c->append == 0 && addnullc != 0)
|
||||
c->buffer[c->size-1] = '\0';
|
||||
}
|
||||
|
||||
return s;
|
||||
@@ -123,7 +122,10 @@ fmemopen_seek (void *cookie, _IO_off64_t *p, int w)
|
||||
}
|
||||
|
||||
if (np < 0 || (size_t) np > c->size)
|
||||
return -1;
|
||||
{
|
||||
__set_errno (EINVAL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*p = c->pos = np;
|
||||
|
||||
|
||||
+35
-14
@@ -43,25 +43,29 @@ static _IO_ssize_t
|
||||
_IO_cookie_read (_IO_FILE *fp, void *buf, _IO_ssize_t size)
|
||||
{
|
||||
struct _IO_cookie_file *cfile = (struct _IO_cookie_file *) fp;
|
||||
cookie_read_function_t *read_cb = cfile->__io_functions.read;
|
||||
PTR_DEMANGLE (read_cb);
|
||||
|
||||
if (cfile->__io_functions.read == NULL)
|
||||
if (read_cb == NULL)
|
||||
return -1;
|
||||
|
||||
return cfile->__io_functions.read (cfile->__cookie, buf, size);
|
||||
return read_cb (cfile->__cookie, buf, size);
|
||||
}
|
||||
|
||||
static _IO_ssize_t
|
||||
_IO_cookie_write (_IO_FILE *fp, const void *buf, _IO_ssize_t size)
|
||||
{
|
||||
struct _IO_cookie_file *cfile = (struct _IO_cookie_file *) fp;
|
||||
cookie_write_function_t *write_cb = cfile->__io_functions.write;
|
||||
PTR_DEMANGLE (write_cb);
|
||||
|
||||
if (cfile->__io_functions.write == NULL)
|
||||
if (write_cb == NULL)
|
||||
{
|
||||
fp->_flags |= _IO_ERR_SEEN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_IO_ssize_t n = cfile->__io_functions.write (cfile->__cookie, buf, size);
|
||||
_IO_ssize_t n = write_cb (cfile->__cookie, buf, size);
|
||||
if (n < size)
|
||||
fp->_flags |= _IO_ERR_SEEN;
|
||||
|
||||
@@ -72,9 +76,11 @@ static _IO_off64_t
|
||||
_IO_cookie_seek (_IO_FILE *fp, _IO_off64_t offset, int dir)
|
||||
{
|
||||
struct _IO_cookie_file *cfile = (struct _IO_cookie_file *) fp;
|
||||
cookie_seek_function_t *seek_cb = cfile->__io_functions.seek;
|
||||
PTR_DEMANGLE (seek_cb);
|
||||
|
||||
return ((cfile->__io_functions.seek == NULL
|
||||
|| (cfile->__io_functions.seek (cfile->__cookie, &offset, dir)
|
||||
return ((seek_cb == NULL
|
||||
|| (seek_cb (cfile->__cookie, &offset, dir)
|
||||
== -1)
|
||||
|| offset == (_IO_off64_t) -1)
|
||||
? _IO_pos_BAD : offset);
|
||||
@@ -84,11 +90,13 @@ static int
|
||||
_IO_cookie_close (_IO_FILE *fp)
|
||||
{
|
||||
struct _IO_cookie_file *cfile = (struct _IO_cookie_file *) fp;
|
||||
cookie_close_function_t *close_cb = cfile->__io_functions.close;
|
||||
PTR_DEMANGLE (close_cb);
|
||||
|
||||
if (cfile->__io_functions.close == NULL)
|
||||
if (close_cb == NULL)
|
||||
return 0;
|
||||
|
||||
return cfile->__io_functions.close (cfile->__cookie);
|
||||
return close_cb (cfile->__cookie);
|
||||
}
|
||||
|
||||
|
||||
@@ -126,6 +134,19 @@ static const struct _IO_jump_t _IO_cookie_jumps = {
|
||||
};
|
||||
|
||||
|
||||
/* Copy the callbacks from SOURCE to *TARGET, with pointer
|
||||
mangling. */
|
||||
static void
|
||||
set_callbacks (_IO_cookie_io_functions_t *target,
|
||||
_IO_cookie_io_functions_t source)
|
||||
{
|
||||
PTR_MANGLE (source.read);
|
||||
PTR_MANGLE (source.write);
|
||||
PTR_MANGLE (source.seek);
|
||||
PTR_MANGLE (source.close);
|
||||
*target = source;
|
||||
}
|
||||
|
||||
void
|
||||
_IO_cookie_init (struct _IO_cookie_file *cfile, int read_write,
|
||||
void *cookie, _IO_cookie_io_functions_t io_functions)
|
||||
@@ -134,7 +155,7 @@ _IO_cookie_init (struct _IO_cookie_file *cfile, int read_write,
|
||||
_IO_JUMPS (&cfile->__fp) = &_IO_cookie_jumps;
|
||||
|
||||
cfile->__cookie = cookie;
|
||||
cfile->__io_functions = io_functions;
|
||||
set_callbacks (&cfile->__io_functions, io_functions);
|
||||
|
||||
_IO_file_init (&cfile->__fp);
|
||||
|
||||
@@ -205,14 +226,14 @@ attribute_compat_text_section
|
||||
_IO_old_cookie_seek (_IO_FILE *fp, _IO_off64_t offset, int dir)
|
||||
{
|
||||
struct _IO_cookie_file *cfile = (struct _IO_cookie_file *) fp;
|
||||
int (*seek) (_IO_FILE *, _IO_off_t, int);
|
||||
int ret;
|
||||
int (*seek_cb) (_IO_FILE *, _IO_off_t, int)
|
||||
= (int (*) (_IO_FILE *, _IO_off_t, int)) cfile->__io_functions.seek;;
|
||||
PTR_DEMANGLE (seek_cb);
|
||||
|
||||
seek = (int (*)(_IO_FILE *, _IO_off_t, int)) cfile->__io_functions.seek;
|
||||
if (seek == NULL)
|
||||
if (seek_cb == NULL)
|
||||
return _IO_pos_BAD;
|
||||
|
||||
ret = seek (cfile->__cookie, offset, dir);
|
||||
int ret = seek_cb (cfile->__cookie, offset, dir);
|
||||
|
||||
return (ret == -1) ? _IO_pos_BAD : ret;
|
||||
}
|
||||
|
||||
@@ -299,6 +299,27 @@ extern __thread struct __locale_data *const *_nl_current_##category \
|
||||
|
||||
#endif
|
||||
|
||||
/* Extract CATEGORY locale's string for ITEM. */
|
||||
static inline const char *
|
||||
_nl_lookup (locale_t l, int category, int item)
|
||||
{
|
||||
return l->__locales[category]->values[_NL_ITEM_INDEX (item)].string;
|
||||
}
|
||||
|
||||
/* Extract CATEGORY locale's wide string for ITEM. */
|
||||
static inline const wchar_t *
|
||||
_nl_lookup_wstr (locale_t l, int category, int item)
|
||||
{
|
||||
return (wchar_t *) l->__locales[category]
|
||||
->values[_NL_ITEM_INDEX (item)].wstr;
|
||||
}
|
||||
|
||||
/* Extract the CATEGORY locale's word for ITEM. */
|
||||
static inline uint32_t
|
||||
_nl_lookup_word (locale_t l, int category, int item)
|
||||
{
|
||||
return l->__locales[category]->values[_NL_ITEM_INDEX (item)].word;
|
||||
}
|
||||
|
||||
/* Default search path if no LOCPATH environment variable. */
|
||||
extern const char _nl_default_locale_path[] attribute_hidden;
|
||||
|
||||
@@ -1,3 +1,24 @@
|
||||
2017-06-11 Santhosh Thottingal <santhosh.thottingal@gmail.com>
|
||||
|
||||
[BZ #19922]
|
||||
* locales/iso14651_t1_common: Add collation rules for U+07DA to U+07DF.
|
||||
|
||||
[BZ #19919]
|
||||
* locales/iso14651_t1_common: Correct collation of U+0D36 and U+0D37.
|
||||
|
||||
2016-12-30 Mike Frysinger <vapier@gentoo.org>
|
||||
|
||||
[BZ #20974]
|
||||
* localedata/bs_BA (LC_MESSAGES): Delete "*." from the end of
|
||||
yesexpr and noexpr.
|
||||
|
||||
2016-02-19 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
[BZ #19581]
|
||||
* locales/sr_ME (date_fmt): Remove newline.
|
||||
* locales/sr_RS (date_fmt): Likewise.
|
||||
* locales/sr_RS@latin (date_fmt): Likewise.
|
||||
|
||||
2016-02-08 Mike Frysinger <vapier@gentoo.org>
|
||||
|
||||
* locales/an_ES: Convert to UTF-8 encodings.
|
||||
|
||||
@@ -144,8 +144,8 @@ copy "en_DK"
|
||||
END LC_CTYPE
|
||||
|
||||
LC_MESSAGES
|
||||
yesexpr "<U005E><U005B><U0064><U0044><U0079><U0059><U005D><U002A><U002E>"
|
||||
noexpr "<U005E><U005B><U006E><U004E><U005D><U002A><U002E>"
|
||||
yesexpr "<U005E><U005B><U0064><U0044><U0079><U0059><U005D>"
|
||||
noexpr "<U005E><U005B><U006E><U004E><U005D>"
|
||||
END LC_MESSAGES
|
||||
|
||||
LC_MONETARY
|
||||
|
||||
@@ -1035,9 +1035,9 @@ collating-element <ml-bh> from "<U0D2D><U0D4D>"
|
||||
collating-element <ml-m> from "<U0D2E><U0D4D>"
|
||||
collating-element <ml-y> from "<U0D2F><U0D4D>"
|
||||
collating-element <ml-v> from "<U0D35><U0D4D>"
|
||||
collating-element <ml-s> from "<U0D38><U0D4D>"
|
||||
collating-element <ml-ss> from "<U0D36><U0D4D>"
|
||||
collating-element <ml-sh> from "<U0D37><U0D4D>"
|
||||
collating-element <ml-s> from "<U0D38><U0D4D>"
|
||||
collating-element <ml-h> from "<U0D39><U0D4D>"
|
||||
collating-element <ml-zh> from "<U0D34><U0D4D>"
|
||||
collating-element <ml-rr> from "<U0D31><U0D4D>"
|
||||
@@ -1096,8 +1096,8 @@ collating-symbol <ml-rra>
|
||||
collating-symbol <ml-la>
|
||||
collating-symbol <ml-lla>
|
||||
collating-symbol <ml-va>
|
||||
collating-symbol <ml-sha>
|
||||
collating-symbol <ml-ssa>
|
||||
collating-symbol <ml-sha>
|
||||
collating-symbol <ml-sa>
|
||||
collating-symbol <ml-ha>
|
||||
collating-symbol <ml-avagrah>
|
||||
@@ -1119,6 +1119,12 @@ collating-symbol <mlvs-o>
|
||||
collating-symbol <mlvs-au>
|
||||
collating-symbol <ml-visarga>
|
||||
collating-symbol <ml-virama>
|
||||
collating-symbol <ml-atomic-chillu-k>
|
||||
collating-symbol <ml-atomic-chillu-n>
|
||||
collating-symbol <ml-atomic-chillu-nn>
|
||||
collating-symbol <ml-atomic-chillu-l>
|
||||
collating-symbol <ml-atomic-chillu-ll>
|
||||
collating-symbol <ml-atomic-chillu-r>
|
||||
#
|
||||
# <BENGALI>
|
||||
#
|
||||
@@ -4545,6 +4551,12 @@ collating-symbol <TIB-subA>
|
||||
<mlvs-o>
|
||||
<mlvs-au>
|
||||
<ml-visarga>
|
||||
<ml-atomic-chillu-k>
|
||||
<ml-atomic-chillu-n>
|
||||
<ml-atomic-chillu-nn>
|
||||
<ml-atomic-chillu-l>
|
||||
<ml-atomic-chillu-ll>
|
||||
<ml-atomic-chillu-r>
|
||||
#
|
||||
# <BENGALI>
|
||||
#
|
||||
@@ -7245,6 +7257,7 @@ order_start <MALAYALAM>;forward;forward;forward;forward,position
|
||||
<U0D13> <mlvw-o>;<BAS>;<MIN>;IGNORE
|
||||
<U0D14> <mlvw-au>;<BAS>;<MIN>;IGNORE
|
||||
<ml-chillu-k> "<ml-ka><ml-virama>";<BAS>;<MIN>;IGNORE
|
||||
<U0D7F> "<ml-ka><ml-virama>";<ml-atomic-chillu-k>;<MIN>;IGNORE
|
||||
<U0D15> "<ml-ka><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
|
||||
<ml-kh> "<ml-kha><ml-virama>";<BAS>;<MIN>;IGNORE
|
||||
<U0D16> "<ml-kha><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
|
||||
@@ -7273,6 +7286,7 @@ order_start <MALAYALAM>;forward;forward;forward;forward,position
|
||||
<ml-dh> "<ml-dha><ml-virama>";<BAS>;<MIN>;IGNORE
|
||||
<U0D22> "<ml-dha><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
|
||||
<ml-chillu-nn> "<ml-nna><ml-virama>";<BAS>;<MIN>;IGNORE # ണ് = ണ + ് + zwj
|
||||
<U0D7A> "<ml-nna><ml-virama>";<ml-atomic-chillu-nn>;<MIN>;IGNORE
|
||||
<U0D23> "<ml-nna><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE # ണ = ണ + ് + അ
|
||||
<ml-th> "<ml-tha><ml-virama>";<BAS>;<MIN>;IGNORE
|
||||
<U0D24> "<ml-tha><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
|
||||
@@ -7283,6 +7297,7 @@ order_start <MALAYALAM>;forward;forward;forward;forward,position
|
||||
<ml-ddh> "<ml-ddha><ml-virama>";<BAS>;<MIN>;IGNORE
|
||||
<U0D27> "<ml-ddha><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
|
||||
<ml-chillu-n> "<ml-na><ml-virama>";<BAS>;<MIN>;IGNORE # ന്= ന + ് + zwj
|
||||
<U0D7B> "<ml-na><ml-virama>";<ml-atomic-chillu-n>;<MIN>;IGNORE
|
||||
<U0D28> "<ml-na><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE #ന = ന + ് + അ
|
||||
<ml-p> "<ml-pa><ml-virama>";<BAS>;<MIN>;IGNORE
|
||||
<U0D2A> "<ml-pa><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
|
||||
@@ -7298,20 +7313,23 @@ order_start <MALAYALAM>;forward;forward;forward;forward,position
|
||||
<ml-y> "<ml-ya><ml-virama>";<BAS>;<MIN>;IGNORE
|
||||
<U0D2F> "<ml-ya><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
|
||||
<ml-chillu-r> "<ml-ra><ml-virama>";<BAS>;<MIN>;IGNORE # ര = ര + ് + zwj
|
||||
<U0D7C> "<ml-ra><ml-virama>";<ml-atomic-chillu-r>;<MIN>;IGNORE
|
||||
<U0D30> "<ml-ra><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE # ര = ര + ് + അ
|
||||
<ml-chillu-l> <ml-la>;<BAS>;<MIN>;IGNORE # ല് = ല + ് + zwj
|
||||
<U0D7D> "<ml-la><ml-virama>";<ml-atomic-chillu-l>;<MIN>;IGNORE
|
||||
<U0D32> "<ml-la><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE # ല = ല + ് + അ
|
||||
<ml-v> "<ml-va><ml-virama>";<BAS>;<MIN>;IGNORE
|
||||
<U0D35> "<ml-va><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
|
||||
<ml-ss> "<ml-ssa><ml-virama>";<BAS>;<MIN>;IGNORE
|
||||
<U0D37> "<ml-ssa><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
|
||||
<U0D36> "<ml-ssa><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
|
||||
<ml-sh> "<ml-sha><ml-virama>";<BAS>;<MIN>;IGNORE
|
||||
<U0D36> "<ml-sha><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
|
||||
<U0D37> "<ml-sha><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
|
||||
<ml-s> "<ml-sa><ml-virama>";<BAS>;<MIN>;IGNORE
|
||||
<U0D38> "<ml-sa><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
|
||||
<ml-h> "<ml-ha><ml-virama>";<BAS>;<MIN>;IGNORE
|
||||
<U0D39> "<ml-ha><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
|
||||
<ml-chillu-ll> "<ml-lla><ml-virama>";<BAS>;<MIN>;IGNORE # ള് = ള + ് + zwj
|
||||
<U0D7E> "<ml-lla><ml-virama>";<ml-atomic-chillu-ll>;<MIN>;IGNORE
|
||||
<U0D33> "<ml-lla><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE # ള = ള + ് + അ
|
||||
<ml-zh> "<ml-zha><ml-virama>";<BAS>;<MIN>;IGNORE
|
||||
<U0D34> "<ml-zha><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
|
||||
|
||||
@@ -119,7 +119,7 @@ am_pm "";""
|
||||
t_fmt_ampm "<U0025><U0054>"
|
||||
date_fmt "<U0025><U0061><U002c><U0020><U0025><U0065><U002E><U0020>/
|
||||
<U0025><U0062><U0020><U0025><U0059><U002E><U0020><U0020><U0025><U0048>/
|
||||
<U003A><U0025><U004D><U003A><U0025><U0053><U0020><U0025><U005A><U000A>"
|
||||
<U003A><U0025><U004D><U003A><U0025><U0053><U0020><U0025><U005A>"
|
||||
week 7;19971130;4
|
||||
first_weekday 2
|
||||
first_workday 2
|
||||
|
||||
@@ -300,7 +300,7 @@ am_pm "";""
|
||||
t_fmt_ampm "<U0025><U0054>"
|
||||
date_fmt "<U0025><U0061><U002C><U0020><U0025><U0065><U002E><U0020>/
|
||||
<U0025><U0062><U0020><U0025><U0059><U002E><U0020><U0020><U0025><U0048>/
|
||||
<U003A><U0025><U004D><U003A><U0025><U0053><U0020><U0025><U005A><U000A>"
|
||||
<U003A><U0025><U004D><U003A><U0025><U0053><U0020><U0025><U005A>"
|
||||
week 7;19971130;4
|
||||
first_weekday 2
|
||||
first_workday 2
|
||||
|
||||
@@ -120,7 +120,7 @@ am_pm "";""
|
||||
t_fmt_ampm "<U0025><U0054>"
|
||||
date_fmt "<U0025><U0061><U002c><U0020><U0025><U0065><U002E><U0020>/
|
||||
<U0025><U0062><U0020><U0025><U0059><U002E><U0020><U0020><U0025><U0048>/
|
||||
<U003A><U0025><U004D><U003A><U0025><U0053><U0020><U0025><U005A><U000A>"
|
||||
<U003A><U0025><U004D><U003A><U0025><U0053><U0020><U0025><U005A>"
|
||||
week 7;19971130;4
|
||||
first_weekday 2
|
||||
first_workday 2
|
||||
|
||||
+35
-7
@@ -29,7 +29,17 @@ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \
|
||||
tst-malloc-usable tst-realloc tst-posix_memalign \
|
||||
tst-pvalloc tst-memalign tst-mallopt tst-scratch_buffer \
|
||||
tst-malloc-backtrace tst-malloc-thread-exit \
|
||||
tst-malloc-thread-fail
|
||||
tst-malloc-thread-fail tst-malloc-fork-deadlock \
|
||||
tst-mallocfork2 \
|
||||
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 \
|
||||
@@ -43,15 +53,22 @@ 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-backtrace: $(common-objpfx)nptl/libpthread.so \
|
||||
$(common-objpfx)nptl/libpthread_nonshared.a
|
||||
$(objpfx)tst-malloc-thread-exit: $(common-objpfx)nptl/libpthread.so \
|
||||
$(common-objpfx)nptl/libpthread_nonshared.a
|
||||
$(objpfx)tst-malloc-thread-fail: $(common-objpfx)nptl/libpthread.so \
|
||||
$(common-objpfx)nptl/libpthread_nonshared.a
|
||||
$(objpfx)tst-malloc-backtrace: $(shared-thread-library)
|
||||
$(objpfx)tst-malloc-thread-exit: $(shared-thread-library)
|
||||
$(objpfx)tst-malloc-thread-fail: $(shared-thread-library)
|
||||
$(objpfx)tst-malloc-fork-deadlock: $(shared-thread-library)
|
||||
|
||||
# These should be removed by `make clean'.
|
||||
extra-objs = mcheck-init.o libmcheck.a
|
||||
@@ -167,3 +184,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)
|
||||
|
||||
+65
-169
@@ -130,149 +130,43 @@ int __malloc_initialized = -1;
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef NO_THREADS
|
||||
|
||||
/* atfork support. */
|
||||
|
||||
static void *(*save_malloc_hook)(size_t __size, const void *);
|
||||
static void (*save_free_hook) (void *__ptr, const void *);
|
||||
static void *save_arena;
|
||||
/* 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. */
|
||||
|
||||
# ifdef ATFORK_MEM
|
||||
ATFORK_MEM;
|
||||
# endif
|
||||
|
||||
/* Magic value for the thread-specific arena pointer when
|
||||
malloc_atfork() is in use. */
|
||||
|
||||
# define ATFORK_ARENA_PTR ((void *) -1)
|
||||
|
||||
/* The following hooks are used while the `atfork' handling mechanism
|
||||
is active. */
|
||||
|
||||
static void *
|
||||
malloc_atfork (size_t sz, const void *caller)
|
||||
void
|
||||
internal_function
|
||||
__malloc_fork_lock_parent (void)
|
||||
{
|
||||
void *victim;
|
||||
|
||||
if (thread_arena == ATFORK_ARENA_PTR)
|
||||
{
|
||||
/* We are the only thread that may allocate at all. */
|
||||
if (save_malloc_hook != malloc_check)
|
||||
{
|
||||
return _int_malloc (&main_arena, sz);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (top_check () < 0)
|
||||
return 0;
|
||||
|
||||
victim = _int_malloc (&main_arena, sz + 1);
|
||||
return mem2mem_check (victim, sz);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Suspend the thread until the `atfork' handlers have completed.
|
||||
By that time, the hooks will have been reset as well, so that
|
||||
mALLOc() can be used again. */
|
||||
(void) mutex_lock (&list_lock);
|
||||
(void) mutex_unlock (&list_lock);
|
||||
return __libc_malloc (sz);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
free_atfork (void *mem, const void *caller)
|
||||
{
|
||||
mstate ar_ptr;
|
||||
mchunkptr p; /* chunk corresponding to mem */
|
||||
|
||||
if (mem == 0) /* free(0) has no effect */
|
||||
return;
|
||||
|
||||
p = mem2chunk (mem); /* do not bother to replicate free_check here */
|
||||
|
||||
if (chunk_is_mmapped (p)) /* release mmapped memory. */
|
||||
{
|
||||
munmap_chunk (p);
|
||||
return;
|
||||
}
|
||||
|
||||
ar_ptr = arena_for_chunk (p);
|
||||
_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). */
|
||||
|
||||
static void
|
||||
ptmalloc_lock_all (void)
|
||||
{
|
||||
mstate ar_ptr;
|
||||
|
||||
if (__malloc_initialized < 1)
|
||||
return;
|
||||
|
||||
/* We do not acquire free_list_lock here because we completely
|
||||
reconstruct free_list in ptmalloc_unlock_all2. */
|
||||
reconstruct free_list in __malloc_fork_unlock_child. */
|
||||
|
||||
if (mutex_trylock (&list_lock))
|
||||
{
|
||||
if (thread_arena == ATFORK_ARENA_PTR)
|
||||
/* This is the same thread which already locks the global list.
|
||||
Just bump the counter. */
|
||||
goto out;
|
||||
(void) mutex_lock (&list_lock);
|
||||
|
||||
/* This thread has to wait its turn. */
|
||||
(void) mutex_lock (&list_lock);
|
||||
}
|
||||
for (ar_ptr = &main_arena;; )
|
||||
for (mstate ar_ptr = &main_arena;; )
|
||||
{
|
||||
(void) mutex_lock (&ar_ptr->mutex);
|
||||
ar_ptr = ar_ptr->next;
|
||||
if (ar_ptr == &main_arena)
|
||||
break;
|
||||
}
|
||||
save_malloc_hook = __malloc_hook;
|
||||
save_free_hook = __free_hook;
|
||||
__malloc_hook = malloc_atfork;
|
||||
__free_hook = free_atfork;
|
||||
/* Only the current thread may perform malloc/free calls now.
|
||||
save_arena will be reattached to the current thread, in
|
||||
ptmalloc_lock_all, 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;
|
||||
|
||||
if (__malloc_initialized < 1)
|
||||
return;
|
||||
|
||||
if (--atfork_recursive_cntr != 0)
|
||||
return;
|
||||
|
||||
/* Replace ATFORK_ARENA_PTR with save_arena.
|
||||
save_arena->attached_threads was not changed in ptmalloc_lock_all
|
||||
and is still correct. */
|
||||
thread_arena = save_arena;
|
||||
__malloc_hook = save_malloc_hook;
|
||||
__free_hook = save_free_hook;
|
||||
for (ar_ptr = &main_arena;; )
|
||||
for (mstate ar_ptr = &main_arena;; )
|
||||
{
|
||||
(void) mutex_unlock (&ar_ptr->mutex);
|
||||
ar_ptr = ar_ptr->next;
|
||||
@@ -282,35 +176,23 @@ 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;
|
||||
|
||||
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
|
||||
/* Push all arenas to the free list, except thread_arena, which is
|
||||
attached to the current thread. */
|
||||
mutex_init (&free_list_lock);
|
||||
if (save_arena != NULL)
|
||||
((mstate) save_arena)->attached_threads = 1;
|
||||
if (thread_arena != NULL)
|
||||
thread_arena->attached_threads = 1;
|
||||
free_list = NULL;
|
||||
for (ar_ptr = &main_arena;; )
|
||||
for (mstate ar_ptr = &main_arena;; )
|
||||
{
|
||||
mutex_init (&ar_ptr->mutex);
|
||||
if (ar_ptr != save_arena)
|
||||
if (ar_ptr != thread_arena)
|
||||
{
|
||||
/* This arena is no longer attached to any thread. */
|
||||
ar_ptr->attached_threads = 0;
|
||||
@@ -323,15 +205,8 @@ ptmalloc_unlock_all2 (void)
|
||||
}
|
||||
|
||||
mutex_init (&list_lock);
|
||||
atfork_recursive_cntr = 0;
|
||||
}
|
||||
|
||||
# else
|
||||
|
||||
# define ptmalloc_unlock_all2 ptmalloc_unlock_all
|
||||
# endif
|
||||
#endif /* !NO_THREADS */
|
||||
|
||||
/* Initialization routine. */
|
||||
#include <string.h>
|
||||
extern char **_environ;
|
||||
@@ -400,7 +275,6 @@ ptmalloc_init (void)
|
||||
#endif
|
||||
|
||||
thread_arena = &main_arena;
|
||||
thread_atfork (ptmalloc_lock_all, ptmalloc_unlock_all, ptmalloc_unlock_all2);
|
||||
const char *s = NULL;
|
||||
if (__glibc_likely (_environ != NULL))
|
||||
{
|
||||
@@ -475,14 +349,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
|
||||
@@ -831,7 +697,8 @@ _int_new_arena (size_t size)
|
||||
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 ptmalloc_lock_all. */
|
||||
but this could result in a deadlock with
|
||||
__malloc_fork_lock_parent. */
|
||||
|
||||
(void) mutex_lock (&a->mutex);
|
||||
|
||||
@@ -839,8 +706,7 @@ _int_new_arena (size_t size)
|
||||
}
|
||||
|
||||
|
||||
/* Remove an arena from free_list. The arena may be in use because it
|
||||
was attached concurrently to a thread by reused_arena below. */
|
||||
/* Remove an arena from free_list. */
|
||||
static mstate
|
||||
get_free_list (void)
|
||||
{
|
||||
@@ -855,7 +721,8 @@ get_free_list (void)
|
||||
free_list = result->next_free;
|
||||
|
||||
/* The arena will be attached to this thread. */
|
||||
++result->attached_threads;
|
||||
assert (result->attached_threads == 0);
|
||||
result->attached_threads = 1;
|
||||
|
||||
detach_arena (replaced_arena);
|
||||
}
|
||||
@@ -872,6 +739,26 @@ get_free_list (void)
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Remove the arena from the free list (if it is present).
|
||||
free_list_lock must have been acquired by the caller. */
|
||||
static void
|
||||
remove_from_free_list (mstate arena)
|
||||
{
|
||||
mstate *previous = &free_list;
|
||||
for (mstate p = free_list; p != NULL; p = p->next_free)
|
||||
{
|
||||
assert (p->attached_threads == 0);
|
||||
if (p == arena)
|
||||
{
|
||||
/* Remove the requested arena from the list. */
|
||||
*previous = p->next_free;
|
||||
break;
|
||||
}
|
||||
else
|
||||
previous = &p->next_free;
|
||||
}
|
||||
}
|
||||
|
||||
/* Lock and return an arena that can be reused for memory allocation.
|
||||
Avoid AVOID_ARENA as we have already failed to allocate memory in
|
||||
it and it is currently locked. */
|
||||
@@ -908,27 +795,36 @@ reused_arena (mstate avoid_arena)
|
||||
{
|
||||
result = result->next;
|
||||
if (result == begin)
|
||||
break;
|
||||
/* We looped around the arena list. We could not find any
|
||||
arena that was either not corrupted or not the one we
|
||||
wanted to avoid. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* We could not find any arena that was either not corrupted or not the one
|
||||
we wanted to avoid. */
|
||||
if (result == begin || result == avoid_arena)
|
||||
return NULL;
|
||||
|
||||
/* No arena available without contention. Wait for the next in line. */
|
||||
LIBC_PROBE (memory_arena_reuse_wait, 3, &result->mutex, result, avoid_arena);
|
||||
(void) mutex_lock (&result->mutex);
|
||||
|
||||
out:
|
||||
/* Attach the arena to the current thread. Note that we may have
|
||||
selected an arena which was on free_list. */
|
||||
/* Attach the arena to the current thread. */
|
||||
{
|
||||
/* Update the arena thread attachment counters. */
|
||||
mstate replaced_arena = thread_arena;
|
||||
(void) mutex_lock (&free_list_lock);
|
||||
detach_arena (replaced_arena);
|
||||
|
||||
/* We may have picked up an arena on the free list. We need to
|
||||
preserve the invariant that no arena on the free list has a
|
||||
positive attached_threads counter (otherwise,
|
||||
arena_thread_freeres cannot use the counter to determine if the
|
||||
arena needs to be put on the free list). We unconditionally
|
||||
remove the selected arena from the free list. The caller of
|
||||
reused_arena checked the free list and observed it to be empty,
|
||||
so the list is very short. */
|
||||
remove_from_free_list (result);
|
||||
|
||||
++result->attached_threads;
|
||||
|
||||
(void) mutex_unlock (&free_list_lock);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 */
|
||||
+1
-4
@@ -244,6 +244,7 @@
|
||||
/* For ALIGN_UP et. al. */
|
||||
#include <libc-internal.h>
|
||||
|
||||
#include <malloc/malloc-internal.h>
|
||||
|
||||
/*
|
||||
Debugging:
|
||||
@@ -1074,10 +1075,6 @@ static void* realloc_check(void* oldmem, size_t bytes,
|
||||
const void *caller);
|
||||
static void* memalign_check(size_t alignment, size_t bytes,
|
||||
const void *caller);
|
||||
#ifndef NO_THREADS
|
||||
static void* malloc_atfork(size_t sz, const void *caller);
|
||||
static void free_atfork(void* mem, const void *caller);
|
||||
#endif
|
||||
|
||||
/* ------------------ MMAP support ------------------ */
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
/* Interposed malloc, version without threading support.
|
||||
Copyright (C) 2016 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#define INTERPOSE_THREADS 0
|
||||
#include "tst-interpose-aux.c"
|
||||
@@ -0,0 +1,20 @@
|
||||
/* Interposed malloc, version with threading support.
|
||||
Copyright (C) 2016 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#define INTERPOSE_THREADS 1
|
||||
#include "tst-interpose-aux.c"
|
||||
@@ -0,0 +1,270 @@
|
||||
/* Minimal malloc implementation for interposition tests.
|
||||
Copyright (C) 2016 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "tst-interpose-aux.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/uio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if INTERPOSE_THREADS
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
/* Print the error message and terminate the process with status 1. */
|
||||
__attribute__ ((noreturn))
|
||||
__attribute__ ((format (printf, 1, 2)))
|
||||
static void *
|
||||
fail (const char *format, ...)
|
||||
{
|
||||
/* This assumes that vsnprintf will not call malloc. It does not do
|
||||
so for the format strings we use. */
|
||||
char message[4096];
|
||||
va_list ap;
|
||||
va_start (ap, format);
|
||||
vsnprintf (message, sizeof (message), format, ap);
|
||||
va_end (ap);
|
||||
|
||||
enum { count = 3 };
|
||||
struct iovec iov[count];
|
||||
|
||||
iov[0].iov_base = (char *) "error: ";
|
||||
iov[1].iov_base = (char *) message;
|
||||
iov[2].iov_base = (char *) "\n";
|
||||
|
||||
for (int i = 0; i < count; ++i)
|
||||
iov[i].iov_len = strlen (iov[i].iov_base);
|
||||
|
||||
int unused __attribute__ ((unused));
|
||||
unused = writev (STDOUT_FILENO, iov, count);
|
||||
_exit (1);
|
||||
}
|
||||
|
||||
#if INTERPOSE_THREADS
|
||||
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
#endif
|
||||
|
||||
static void
|
||||
lock (void)
|
||||
{
|
||||
#if INTERPOSE_THREADS
|
||||
int ret = pthread_mutex_lock (&mutex);
|
||||
if (ret != 0)
|
||||
{
|
||||
errno = ret;
|
||||
fail ("pthread_mutex_lock: %m");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
unlock (void)
|
||||
{
|
||||
#if INTERPOSE_THREADS
|
||||
int ret = pthread_mutex_unlock (&mutex);
|
||||
if (ret != 0)
|
||||
{
|
||||
errno = ret;
|
||||
fail ("pthread_mutex_unlock: %m");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
struct __attribute__ ((aligned (__alignof__ (max_align_t)))) allocation_header
|
||||
{
|
||||
size_t allocation_index;
|
||||
size_t allocation_size;
|
||||
};
|
||||
|
||||
/* Array of known allocations, to track invalid frees. */
|
||||
enum { max_allocations = 65536 };
|
||||
static struct allocation_header *allocations[max_allocations];
|
||||
static size_t allocation_index;
|
||||
static size_t deallocation_count;
|
||||
|
||||
/* Sanity check for successful malloc interposition. */
|
||||
__attribute__ ((destructor))
|
||||
static void
|
||||
check_for_allocations (void)
|
||||
{
|
||||
if (allocation_index == 0)
|
||||
{
|
||||
/* Make sure that malloc is called at least once from libc. */
|
||||
void *volatile ptr = strdup ("ptr");
|
||||
free (ptr);
|
||||
/* Compiler barrier. The strdup function calls malloc, which
|
||||
updates allocation_index, but strdup is marked __THROW, so
|
||||
the compiler could optimize away the reload. */
|
||||
__asm__ volatile ("" ::: "memory");
|
||||
/* If the allocation count is still zero, it means we did not
|
||||
interpose malloc successfully. */
|
||||
if (allocation_index == 0)
|
||||
fail ("malloc does not seem to have been interposed");
|
||||
}
|
||||
}
|
||||
|
||||
static struct allocation_header *get_header (const char *op, void *ptr)
|
||||
{
|
||||
struct allocation_header *header = ((struct allocation_header *) ptr) - 1;
|
||||
if (header->allocation_index >= allocation_index)
|
||||
fail ("%s: %p: invalid allocation index: %zu (not less than %zu)",
|
||||
op, ptr, header->allocation_index, allocation_index);
|
||||
if (allocations[header->allocation_index] != header)
|
||||
fail ("%s: %p: allocation pointer does not point to header, but %p",
|
||||
op, ptr, allocations[header->allocation_index]);
|
||||
return header;
|
||||
}
|
||||
|
||||
/* Internal helper functions. Those must be called while the lock is
|
||||
acquired. */
|
||||
|
||||
static void *
|
||||
malloc_internal (size_t size)
|
||||
{
|
||||
if (allocation_index == max_allocations)
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
size_t allocation_size = size + sizeof (struct allocation_header);
|
||||
if (allocation_size < size)
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t index = allocation_index++;
|
||||
void *result = mmap (NULL, allocation_size, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if (result == MAP_FAILED)
|
||||
return NULL;
|
||||
allocations[index] = result;
|
||||
*allocations[index] = (struct allocation_header)
|
||||
{
|
||||
.allocation_index = index,
|
||||
.allocation_size = allocation_size
|
||||
};
|
||||
return allocations[index] + 1;
|
||||
}
|
||||
|
||||
static void
|
||||
free_internal (const char *op, struct allocation_header *header)
|
||||
{
|
||||
size_t index = header->allocation_index;
|
||||
int result = mprotect (header, header->allocation_size, PROT_NONE);
|
||||
if (result != 0)
|
||||
fail ("%s: mprotect (%p, %zu): %m", op, header, header->allocation_size);
|
||||
/* Catch double-free issues. */
|
||||
allocations[index] = NULL;
|
||||
++deallocation_count;
|
||||
}
|
||||
|
||||
static void *
|
||||
realloc_internal (void *ptr, size_t new_size)
|
||||
{
|
||||
struct allocation_header *header = get_header ("realloc", ptr);
|
||||
size_t old_size = header->allocation_size - sizeof (struct allocation_header);
|
||||
if (old_size >= new_size)
|
||||
return ptr;
|
||||
|
||||
void *newptr = malloc_internal (new_size);
|
||||
if (newptr == NULL)
|
||||
return NULL;
|
||||
memcpy (newptr, ptr, old_size);
|
||||
free_internal ("realloc", header);
|
||||
return newptr;
|
||||
}
|
||||
|
||||
/* Public interfaces. These functions must perform locking. */
|
||||
|
||||
size_t
|
||||
malloc_allocation_count (void)
|
||||
{
|
||||
lock ();
|
||||
size_t count = allocation_index;
|
||||
unlock ();
|
||||
return count;
|
||||
}
|
||||
|
||||
size_t
|
||||
malloc_deallocation_count (void)
|
||||
{
|
||||
lock ();
|
||||
size_t count = deallocation_count;
|
||||
unlock ();
|
||||
return count;
|
||||
}
|
||||
void *
|
||||
malloc (size_t size)
|
||||
{
|
||||
lock ();
|
||||
void *result = malloc_internal (size);
|
||||
unlock ();
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
free (void *ptr)
|
||||
{
|
||||
if (ptr == NULL)
|
||||
return;
|
||||
lock ();
|
||||
struct allocation_header *header = get_header ("free", ptr);
|
||||
free_internal ("free", header);
|
||||
unlock ();
|
||||
}
|
||||
|
||||
void *
|
||||
calloc (size_t a, size_t b)
|
||||
{
|
||||
if (b > 0 && a > SIZE_MAX / b)
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
lock ();
|
||||
/* malloc_internal uses mmap, so the memory is zeroed. */
|
||||
void *result = malloc_internal (a * b);
|
||||
unlock ();
|
||||
return result;
|
||||
}
|
||||
|
||||
void *
|
||||
realloc (void *ptr, size_t n)
|
||||
{
|
||||
if (n ==0)
|
||||
{
|
||||
free (ptr);
|
||||
return NULL;
|
||||
}
|
||||
else if (ptr == NULL)
|
||||
return malloc (n);
|
||||
else
|
||||
{
|
||||
lock ();
|
||||
void *result = realloc_internal (ptr, n);
|
||||
unlock ();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/* Statistics interface for the minimal malloc implementation.
|
||||
Copyright (C) 2016 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef TST_INTERPOSE_AUX_H
|
||||
#define TST_INTERPOSE_AUX_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/* Return the number of allocations performed. */
|
||||
size_t malloc_allocation_count (void);
|
||||
|
||||
/* Return the number of deallocations performed. */
|
||||
size_t malloc_deallocation_count (void);
|
||||
|
||||
#endif /* TST_INTERPOSE_AUX_H */
|
||||
@@ -0,0 +1,20 @@
|
||||
/* Malloc interposition test, dynamically-linked version without threads.
|
||||
Copyright (C) 2016 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#define INTERPOSE_THREADS 0
|
||||
#include "tst-interpose-skeleton.c"
|
||||
@@ -0,0 +1,210 @@
|
||||
/* Test driver for malloc interposition tests.
|
||||
Copyright (C) 2016 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if INTERPOSE_THREADS
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
static int do_test (void);
|
||||
#define TEST_FUNCTION do_test ()
|
||||
#include "../test-skeleton.c"
|
||||
|
||||
/* Fills BUFFER with a test string. */
|
||||
static void
|
||||
line_string (int number, char *buffer, size_t length)
|
||||
{
|
||||
for (size_t i = 0; i < length - 2; ++i)
|
||||
buffer[i] = 'A' + ((number + i) % 26);
|
||||
buffer[length - 2] = '\n';
|
||||
buffer[length - 1] = '\0';
|
||||
}
|
||||
|
||||
/* Perform the tests. */
|
||||
static void *
|
||||
run_tests (void *closure)
|
||||
{
|
||||
char *temp_file_path;
|
||||
int fd = create_temp_file ("tst-malloc-interpose", &temp_file_path);
|
||||
if (fd < 0)
|
||||
_exit (1);
|
||||
|
||||
/* Line lengths excluding the line terminator. */
|
||||
static const int line_lengths[] = { 0, 45, 80, 2, 8201, 0, 17, -1 };
|
||||
|
||||
/* Fill the test file with data. */
|
||||
{
|
||||
FILE *fp = fdopen (fd, "w");
|
||||
for (int lineno = 0; line_lengths[lineno] >= 0; ++lineno)
|
||||
{
|
||||
char buffer[line_lengths[lineno] + 2];
|
||||
line_string (lineno, buffer, sizeof (buffer));
|
||||
fprintf (fp, "%s", buffer);
|
||||
}
|
||||
|
||||
if (ferror (fp))
|
||||
{
|
||||
printf ("error: fprintf: %m\n");
|
||||
_exit (1);
|
||||
}
|
||||
if (fclose (fp) != 0)
|
||||
{
|
||||
printf ("error: fclose: %m\n");
|
||||
_exit (1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Read the test file. This tests libc-internal allocation with
|
||||
realloc. */
|
||||
{
|
||||
FILE *fp = fopen (temp_file_path, "r");
|
||||
|
||||
char *actual = NULL;
|
||||
size_t actual_size = 0;
|
||||
for (int lineno = 0; ; ++lineno)
|
||||
{
|
||||
errno = 0;
|
||||
ssize_t result = getline (&actual, &actual_size, fp);
|
||||
if (result == 0)
|
||||
{
|
||||
printf ("error: invalid return value 0 from getline\n");
|
||||
_exit (1);
|
||||
}
|
||||
if (result < 0 && errno != 0)
|
||||
{
|
||||
printf ("error: getline: %m\n");
|
||||
_exit (1);
|
||||
}
|
||||
if (result < 0 && line_lengths[lineno] >= 0)
|
||||
{
|
||||
printf ("error: unexpected end of file after line %d\n", lineno);
|
||||
_exit (1);
|
||||
}
|
||||
if (result > 0 && line_lengths[lineno] < 0)
|
||||
{
|
||||
printf ("error: no end of file after line %d\n", lineno);
|
||||
_exit (1);
|
||||
}
|
||||
if (result == -1 && line_lengths[lineno] == -1)
|
||||
/* End of file reached as expected. */
|
||||
break;
|
||||
|
||||
if (result != line_lengths[lineno] + 1)
|
||||
{
|
||||
printf ("error: line length mismatch: expected %d, got %zd\n",
|
||||
line_lengths[lineno], result);
|
||||
_exit (1);
|
||||
}
|
||||
|
||||
char expected[line_lengths[lineno] + 2];
|
||||
line_string (lineno, expected, sizeof (expected));
|
||||
if (strcmp (actual, expected) != 0)
|
||||
{
|
||||
printf ("error: line mismatch\n");
|
||||
printf ("error: expected: [[%s]]\n", expected);
|
||||
printf ("error: actual: [[%s]]\n", actual);
|
||||
_exit (1);
|
||||
}
|
||||
}
|
||||
|
||||
if (fclose (fp) != 0)
|
||||
{
|
||||
printf ("error: fclose (after reading): %m\n");
|
||||
_exit (1);
|
||||
}
|
||||
}
|
||||
|
||||
free (temp_file_path);
|
||||
|
||||
/* Make sure that fork is working. */
|
||||
pid_t pid = fork ();
|
||||
if (pid == -1)
|
||||
{
|
||||
printf ("error: fork: %m\n");
|
||||
_exit (1);
|
||||
}
|
||||
enum { exit_code = 55 };
|
||||
if (pid == 0)
|
||||
_exit (exit_code);
|
||||
int status;
|
||||
int ret = waitpid (pid, &status, 0);
|
||||
if (ret < 0)
|
||||
{
|
||||
printf ("error: waitpid: %m\n");
|
||||
_exit (1);
|
||||
}
|
||||
if (!WIFEXITED (status) || WEXITSTATUS (status) != exit_code)
|
||||
{
|
||||
printf ("error: unexpected exit status from child process: %d\n",
|
||||
status);
|
||||
_exit (1);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* This is used to detect if malloc has not been successfully
|
||||
interposed. The interposed malloc does not use brk/sbrk. */
|
||||
static void *initial_brk;
|
||||
__attribute__ ((constructor))
|
||||
static void
|
||||
set_initial_brk (void)
|
||||
{
|
||||
initial_brk = sbrk (0);
|
||||
}
|
||||
|
||||
/* Terminate the process if the break value has been changed. */
|
||||
__attribute__ ((destructor))
|
||||
static void
|
||||
check_brk (void)
|
||||
{
|
||||
void *current = sbrk (0);
|
||||
if (current != initial_brk)
|
||||
{
|
||||
printf ("error: brk changed from %p to %p; no interposition?\n",
|
||||
initial_brk, current);
|
||||
_exit (1);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
check_brk ();
|
||||
|
||||
#if INTERPOSE_THREADS
|
||||
pthread_t thr;
|
||||
int ret;
|
||||
if ((ret = pthread_create (&thr, NULL, run_tests, NULL)) != 0)
|
||||
{
|
||||
errno = ret;
|
||||
printf ("error: %s failed: %m\n", __func__);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
#else
|
||||
run_tests (NULL);
|
||||
#endif
|
||||
|
||||
check_brk ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/* Malloc interposition test, static version without threads.
|
||||
Copyright (C) 2016 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "tst-interpose-nothread.c"
|
||||
@@ -0,0 +1,19 @@
|
||||
/* Malloc interposition test, static version with threads.
|
||||
Copyright (C) 2016 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "tst-interpose-nothread.c"
|
||||
@@ -0,0 +1,20 @@
|
||||
/* Malloc interposition test, dynamically-linked version with threads.
|
||||
Copyright (C) 2016 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#define INTERPOSE_THREADS 1
|
||||
#include "tst-interpose-skeleton.c"
|
||||
@@ -0,0 +1,220 @@
|
||||
/* Test concurrent fork, getline, and fflush (NULL).
|
||||
Copyright (C) 2016 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <malloc.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
static int do_test (void);
|
||||
#define TEST_FUNCTION do_test ()
|
||||
#include "../test-skeleton.c"
|
||||
|
||||
enum {
|
||||
/* Number of threads which call fork. */
|
||||
fork_thread_count = 4,
|
||||
/* Number of threads which call getline (and, indirectly,
|
||||
malloc). */
|
||||
read_thread_count = 8,
|
||||
};
|
||||
|
||||
static bool termination_requested;
|
||||
|
||||
static void *
|
||||
fork_thread_function (void *closure)
|
||||
{
|
||||
while (!__atomic_load_n (&termination_requested, __ATOMIC_RELAXED))
|
||||
{
|
||||
pid_t pid = fork ();
|
||||
if (pid < 0)
|
||||
{
|
||||
printf ("error: fork: %m\n");
|
||||
abort ();
|
||||
}
|
||||
else if (pid == 0)
|
||||
_exit (17);
|
||||
|
||||
int status;
|
||||
if (waitpid (pid, &status, 0) < 0)
|
||||
{
|
||||
printf ("error: waitpid: %m\n");
|
||||
abort ();
|
||||
}
|
||||
if (!WIFEXITED (status) || WEXITSTATUS (status) != 17)
|
||||
{
|
||||
printf ("error: waitpid returned invalid status: %d\n", status);
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char *file_to_read;
|
||||
|
||||
static void *
|
||||
read_thread_function (void *closure)
|
||||
{
|
||||
FILE *f = fopen (file_to_read, "r");
|
||||
if (f == NULL)
|
||||
{
|
||||
printf ("error: fopen (%s): %m\n", file_to_read);
|
||||
abort ();
|
||||
}
|
||||
|
||||
while (!__atomic_load_n (&termination_requested, __ATOMIC_RELAXED))
|
||||
{
|
||||
rewind (f);
|
||||
char *line = NULL;
|
||||
size_t line_allocated = 0;
|
||||
ssize_t ret = getline (&line, &line_allocated, f);
|
||||
if (ret < 0)
|
||||
{
|
||||
printf ("error: getline: %m\n");
|
||||
abort ();
|
||||
}
|
||||
free (line);
|
||||
}
|
||||
fclose (f);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *
|
||||
flushall_thread_function (void *closure)
|
||||
{
|
||||
while (!__atomic_load_n (&termination_requested, __ATOMIC_RELAXED))
|
||||
if (fflush (NULL) != 0)
|
||||
{
|
||||
printf ("error: fflush (NULL): %m\n");
|
||||
abort ();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
create_threads (pthread_t *threads, size_t count, void *(*func) (void *))
|
||||
{
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
{
|
||||
int ret = pthread_create (threads + i, NULL, func, NULL);
|
||||
if (ret != 0)
|
||||
{
|
||||
errno = ret;
|
||||
printf ("error: pthread_create: %m\n");
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
join_threads (pthread_t *threads, size_t count)
|
||||
{
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
{
|
||||
int ret = pthread_join (threads[i], NULL);
|
||||
if (ret != 0)
|
||||
{
|
||||
errno = ret;
|
||||
printf ("error: pthread_join: %m\n");
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Create a file which consists of a single long line, and assigns
|
||||
file_to_read. The hope is that this triggers an allocation in
|
||||
getline which needs a lock. */
|
||||
static void
|
||||
create_file_with_large_line (void)
|
||||
{
|
||||
int fd = create_temp_file ("bug19431-large-line", &file_to_read);
|
||||
if (fd < 0)
|
||||
{
|
||||
printf ("error: create_temp_file: %m\n");
|
||||
abort ();
|
||||
}
|
||||
FILE *f = fdopen (fd, "w+");
|
||||
if (f == NULL)
|
||||
{
|
||||
printf ("error: fdopen: %m\n");
|
||||
abort ();
|
||||
}
|
||||
for (int i = 0; i < 50000; ++i)
|
||||
fputc ('x', f);
|
||||
fputc ('\n', f);
|
||||
if (ferror (f))
|
||||
{
|
||||
printf ("error: fputc: %m\n");
|
||||
abort ();
|
||||
}
|
||||
if (fclose (f) != 0)
|
||||
{
|
||||
printf ("error: fclose: %m\n");
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
/* Make sure that we do not exceed the arena limit with the number
|
||||
of threads we configured. */
|
||||
if (mallopt (M_ARENA_MAX, 400) == 0)
|
||||
{
|
||||
printf ("error: mallopt (M_ARENA_MAX) failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Leave some room for shutting down all threads gracefully. */
|
||||
int timeout = 3;
|
||||
if (timeout > TIMEOUT)
|
||||
timeout = TIMEOUT - 1;
|
||||
|
||||
create_file_with_large_line ();
|
||||
|
||||
pthread_t fork_threads[fork_thread_count];
|
||||
create_threads (fork_threads, fork_thread_count, fork_thread_function);
|
||||
pthread_t read_threads[read_thread_count];
|
||||
create_threads (read_threads, read_thread_count, read_thread_function);
|
||||
pthread_t flushall_threads[1];
|
||||
create_threads (flushall_threads, 1, flushall_thread_function);
|
||||
|
||||
struct timespec ts = {timeout, 0};
|
||||
if (nanosleep (&ts, NULL))
|
||||
{
|
||||
printf ("error: error: nanosleep: %m\n");
|
||||
abort ();
|
||||
}
|
||||
|
||||
__atomic_store_n (&termination_requested, true, __ATOMIC_RELAXED);
|
||||
|
||||
join_threads (flushall_threads, 1);
|
||||
join_threads (read_threads, read_thread_count);
|
||||
join_threads (fork_threads, fork_thread_count);
|
||||
|
||||
free (file_to_read);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
/* Test case for async-signal-safe fork (with respect to 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; see the file COPYING.LIB. If
|
||||
not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* This test will fail if the process is multi-threaded because we
|
||||
only have an async-signal-safe fork in the single-threaded case
|
||||
(where we skip acquiring the malloc heap locks).
|
||||
|
||||
This test only checks async-signal-safety with regards to malloc;
|
||||
other, more rarely-used glibc subsystems could have locks which
|
||||
still make fork unsafe, even in single-threaded processes. */
|
||||
|
||||
#include <errno.h>
|
||||
#include <sched.h>
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/wait.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* How many malloc objects to keep arond. */
|
||||
enum { malloc_objects = 1009 };
|
||||
|
||||
/* The maximum size of an object. */
|
||||
enum { malloc_maximum_size = 70000 };
|
||||
|
||||
/* How many signals need to be delivered before the test exits. */
|
||||
enum { signal_count = 1000 };
|
||||
|
||||
|
||||
/* Process ID of the subprocess which sends SIGUSR1 signals. */
|
||||
static pid_t sigusr1_sender_pid;
|
||||
|
||||
/* Set to 1 if SIGUSR1 is received. Used to detect a signal during
|
||||
malloc/free. */
|
||||
static volatile sig_atomic_t sigusr1_received;
|
||||
|
||||
/* Periodically set to 1, to indicate that the process is making
|
||||
progress. Checked by liveness_signal_handler. */
|
||||
static volatile sig_atomic_t progress_indicator = 1;
|
||||
|
||||
/* Write the message to standard output. Usable from signal
|
||||
handlers. */
|
||||
static void
|
||||
write_message (const char *str)
|
||||
{
|
||||
write (STDOUT_FILENO, str, strlen (str));
|
||||
}
|
||||
|
||||
static void
|
||||
sigusr1_handler (int signo)
|
||||
{
|
||||
/* Let the main program make progress, by temporarily suspending
|
||||
signals from the subprocess. */
|
||||
if (sigusr1_received)
|
||||
return;
|
||||
/* sigusr1_sender_pid might not be initialized in the parent when
|
||||
the first SIGUSR1 signal arrives. */
|
||||
if (sigusr1_sender_pid > 0 && kill (sigusr1_sender_pid, SIGSTOP) != 0)
|
||||
{
|
||||
write_message ("error: kill (SIGSTOP)\n");
|
||||
abort ();
|
||||
}
|
||||
sigusr1_received = 1;
|
||||
|
||||
/* Perform a fork with a trivial subprocess. */
|
||||
pid_t pid = fork ();
|
||||
if (pid == -1)
|
||||
{
|
||||
write_message ("error: fork\n");
|
||||
abort ();
|
||||
}
|
||||
if (pid == 0)
|
||||
_exit (0);
|
||||
int status;
|
||||
int ret = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0));
|
||||
if (ret < 0)
|
||||
{
|
||||
write_message ("error: waitpid\n");
|
||||
abort ();
|
||||
}
|
||||
if (status != 0)
|
||||
{
|
||||
write_message ("error: unexpected exit status from subprocess\n");
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
liveness_signal_handler (int signo)
|
||||
{
|
||||
if (progress_indicator)
|
||||
progress_indicator = 0;
|
||||
else
|
||||
write_message ("warning: process seems to be stuck\n");
|
||||
}
|
||||
|
||||
static void
|
||||
__attribute__ ((noreturn))
|
||||
signal_sender (int signo, bool sleep)
|
||||
{
|
||||
pid_t target = getppid ();
|
||||
while (true)
|
||||
{
|
||||
if (kill (target, signo) != 0)
|
||||
{
|
||||
dprintf (STDOUT_FILENO, "error: kill: %m\n");
|
||||
abort ();
|
||||
}
|
||||
if (sleep)
|
||||
usleep (1 * 1000 * 1000);
|
||||
else
|
||||
/* Reduce the rate at which we send signals. */
|
||||
sched_yield ();
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
struct sigaction action =
|
||||
{
|
||||
.sa_handler = sigusr1_handler,
|
||||
};
|
||||
sigemptyset (&action.sa_mask);
|
||||
|
||||
if (sigaction (SIGUSR1, &action, NULL) != 0)
|
||||
{
|
||||
printf ("error: sigaction: %m");
|
||||
return 1;
|
||||
}
|
||||
|
||||
action.sa_handler = liveness_signal_handler;
|
||||
if (sigaction (SIGUSR2, &action, NULL) != 0)
|
||||
{
|
||||
printf ("error: sigaction: %m");
|
||||
return 1;
|
||||
}
|
||||
|
||||
pid_t sigusr2_sender_pid = fork ();
|
||||
if (sigusr2_sender_pid == 0)
|
||||
signal_sender (SIGUSR2, true);
|
||||
sigusr1_sender_pid = fork ();
|
||||
if (sigusr1_sender_pid == 0)
|
||||
signal_sender (SIGUSR1, false);
|
||||
|
||||
void *objects[malloc_objects] = {};
|
||||
unsigned signals = 0;
|
||||
unsigned seed = 1;
|
||||
time_t last_report = 0;
|
||||
while (signals < signal_count)
|
||||
{
|
||||
progress_indicator = 1;
|
||||
int slot = rand_r (&seed) % malloc_objects;
|
||||
size_t size = rand_r (&seed) % malloc_maximum_size;
|
||||
if (kill (sigusr1_sender_pid, SIGCONT) != 0)
|
||||
{
|
||||
printf ("error: kill (SIGCONT): %m\n");
|
||||
signal (SIGUSR1, SIG_IGN);
|
||||
kill (sigusr1_sender_pid, SIGKILL);
|
||||
kill (sigusr2_sender_pid, SIGKILL);
|
||||
return 1;
|
||||
}
|
||||
sigusr1_received = false;
|
||||
free (objects[slot]);
|
||||
objects[slot] = malloc (size);
|
||||
if (sigusr1_received)
|
||||
{
|
||||
++signals;
|
||||
time_t current = time (0);
|
||||
if (current != last_report)
|
||||
{
|
||||
printf ("info: SIGUSR1 signal count: %u\n", signals);
|
||||
last_report = current;
|
||||
}
|
||||
}
|
||||
if (objects[slot] == NULL)
|
||||
{
|
||||
printf ("error: malloc: %m\n");
|
||||
signal (SIGUSR1, SIG_IGN);
|
||||
kill (sigusr1_sender_pid, SIGKILL);
|
||||
kill (sigusr2_sender_pid, SIGKILL);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Clean up allocations. */
|
||||
for (int slot = 0; slot < malloc_objects; ++slot)
|
||||
free (objects[slot]);
|
||||
|
||||
/* Terminate the signal-sending subprocess. The SIGUSR1 handler
|
||||
should no longer run because it uses sigusr1_sender_pid. */
|
||||
signal (SIGUSR1, SIG_IGN);
|
||||
kill (sigusr1_sender_pid, SIGKILL);
|
||||
kill (sigusr2_sender_pid, SIGKILL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define TIMEOUT 20
|
||||
|
||||
#define TEST_FUNCTION do_test ()
|
||||
#include "../test-skeleton.c"
|
||||
@@ -0,0 +1,42 @@
|
||||
/* Example for creating a struct dirent object for use with glob.
|
||||
Copyright (C) 2016 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct dirent *
|
||||
mkdirent (const char *name)
|
||||
{
|
||||
size_t dirent_size = offsetof (struct dirent, d_name) + 1;
|
||||
size_t name_length = strlen (name);
|
||||
size_t total_size = dirent_size + name_length;
|
||||
if (total_size < dirent_size)
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
struct dirent *result = malloc (total_size);
|
||||
if (result == NULL)
|
||||
return NULL;
|
||||
result->d_type = DT_UNKNOWN;
|
||||
result->d_ino = 1; /* Do not skip this entry. */
|
||||
memcpy (result->d_name, name, name_length + 1);
|
||||
return result;
|
||||
}
|
||||
@@ -1051,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
|
||||
|
||||
+38
-1
@@ -237,7 +237,44 @@ function used to read the contents of a directory. It is used if the
|
||||
@code{GLOB_ALTDIRFUNC} bit is set in the flag parameter. The type of
|
||||
this field is @w{@code{struct dirent *(*) (void *)}}.
|
||||
|
||||
This is a GNU extension.
|
||||
An implementation of @code{gl_readdir} needs to initialize the following
|
||||
members of the @code{struct dirent} object:
|
||||
|
||||
@table @code
|
||||
@item d_type
|
||||
This member should be set to the file type of the entry if it is known.
|
||||
Otherwise, the value @code{DT_UNKNOWN} can be used. The @code{glob}
|
||||
function may use the specified file type to avoid callbacks in cases
|
||||
where the file type indicates that the data is not required.
|
||||
|
||||
@item d_ino
|
||||
This member needs to be non-zero, otherwise @code{glob} may skip the
|
||||
current entry and call the @code{gl_readdir} callback function again to
|
||||
retrieve another entry.
|
||||
|
||||
@item d_name
|
||||
This member must be set to the name of the entry. It must be
|
||||
null-terminated.
|
||||
@end table
|
||||
|
||||
The example below shows how to allocate a @code{struct dirent} object
|
||||
containing a given name.
|
||||
|
||||
@smallexample
|
||||
@include mkdirent.c.texi
|
||||
@end smallexample
|
||||
|
||||
The @code{glob} function reads the @code{struct dirent} members listed
|
||||
above and makes a copy of the file name in the @code{d_name} member
|
||||
immediately after the @code{gl_readdir} callback function returns.
|
||||
Future invocations of any of the callback functions may dealloacte or
|
||||
reuse the buffer. It is the responsibility of the caller of the
|
||||
@code{glob} function to allocate and deallocate the buffer, around the
|
||||
call to @code{glob} or using the callback functions. For example, an
|
||||
application could allocate the buffer in the @code{gl_readdir} callback
|
||||
function, and deallocate it in the @code{gl_closedir} callback function.
|
||||
|
||||
The @code{gl_readdir} member is a GNU extension.
|
||||
|
||||
@item gl_opendir
|
||||
The address of an alternative implementation of the @code{opendir}
|
||||
|
||||
+2
-1
@@ -100,7 +100,8 @@ $(inst_libdir)/libm.so: $(common-objpfx)format.lds \
|
||||
cat $<; \
|
||||
echo 'GROUP ( $(slibdir)/libm.so$(libm.so-version) ' \
|
||||
'AS_NEEDED ( $(libdir)/libmvec_nonshared.a $(slibdir)/libmvec.so$(libmvec.so-version) ) )' \
|
||||
) > $@
|
||||
) > $@.new
|
||||
mv -f $@.new $@
|
||||
endif
|
||||
|
||||
# Rules for the test suite.
|
||||
|
||||
@@ -1144,6 +1144,7 @@ cos 0x4.7857dp+68
|
||||
cos -0x1.02e34cp+0
|
||||
cos 0xf.f0274p+4
|
||||
cos 0x3.042d88p+0
|
||||
cos 0x1.8475e5afd4481p+0
|
||||
|
||||
cosh 0
|
||||
cosh -0
|
||||
@@ -3780,6 +3781,7 @@ sin min
|
||||
sin -min
|
||||
sin min_subnorm
|
||||
sin -min_subnorm
|
||||
sin 0x1.8475e5afd4481p+0
|
||||
|
||||
sincos 0
|
||||
sincos -0
|
||||
@@ -3814,6 +3816,7 @@ sincos min
|
||||
sincos -min
|
||||
sincos min_subnorm
|
||||
sincos -min_subnorm
|
||||
sincos 0x1.8475e5afd4481p+0
|
||||
|
||||
sinh 0
|
||||
sinh -0
|
||||
|
||||
@@ -103416,6 +103416,75 @@ cos 0x3.042d88p+0
|
||||
= cos tonearest ldbl-128ibm 0x3.042d88p+0L : -0xf.dfe6f2169e24f276e8027d91bcp-4L : inexact-ok
|
||||
= cos towardzero ldbl-128ibm 0x3.042d88p+0L : -0xf.dfe6f2169e24f276e8027d91b8p-4L : inexact-ok
|
||||
= cos upward ldbl-128ibm 0x3.042d88p+0L : -0xf.dfe6f2169e24f276e8027d91b8p-4L : inexact-ok
|
||||
cos 0x1.8475e5afd4481p+0
|
||||
= cos downward flt-32 0x1.8475e6p+0f : 0xd.a8263p-8f : inexact-ok
|
||||
= cos tonearest flt-32 0x1.8475e6p+0f : 0xd.a8263p-8f : inexact-ok
|
||||
= cos towardzero flt-32 0x1.8475e6p+0f : 0xd.a8263p-8f : inexact-ok
|
||||
= cos upward flt-32 0x1.8475e6p+0f : 0xd.a8264p-8f : inexact-ok
|
||||
= cos downward dbl-64 0x1.8475e6p+0 : 0xd.a8263394be6dp-8 : inexact-ok
|
||||
= cos tonearest dbl-64 0x1.8475e6p+0 : 0xd.a8263394be6dp-8 : inexact-ok
|
||||
= cos towardzero dbl-64 0x1.8475e6p+0 : 0xd.a8263394be6dp-8 : inexact-ok
|
||||
= cos upward dbl-64 0x1.8475e6p+0 : 0xd.a8263394be6d8p-8 : inexact-ok
|
||||
= cos downward ldbl-96-intel 0x1.8475e6p+0L : 0xd.a8263394be6d0e5p-8L : inexact-ok
|
||||
= cos tonearest ldbl-96-intel 0x1.8475e6p+0L : 0xd.a8263394be6d0e6p-8L : inexact-ok
|
||||
= cos towardzero ldbl-96-intel 0x1.8475e6p+0L : 0xd.a8263394be6d0e5p-8L : inexact-ok
|
||||
= cos upward ldbl-96-intel 0x1.8475e6p+0L : 0xd.a8263394be6d0e6p-8L : inexact-ok
|
||||
= cos downward ldbl-96-m68k 0x1.8475e6p+0L : 0xd.a8263394be6d0e5p-8L : inexact-ok
|
||||
= cos tonearest ldbl-96-m68k 0x1.8475e6p+0L : 0xd.a8263394be6d0e6p-8L : inexact-ok
|
||||
= cos towardzero ldbl-96-m68k 0x1.8475e6p+0L : 0xd.a8263394be6d0e5p-8L : inexact-ok
|
||||
= cos upward ldbl-96-m68k 0x1.8475e6p+0L : 0xd.a8263394be6d0e6p-8L : inexact-ok
|
||||
= cos downward ldbl-128 0x1.8475e6p+0L : 0xd.a8263394be6d0e58c1c35a8a3bap-8L : inexact-ok
|
||||
= cos tonearest ldbl-128 0x1.8475e6p+0L : 0xd.a8263394be6d0e58c1c35a8a3bap-8L : inexact-ok
|
||||
= cos towardzero ldbl-128 0x1.8475e6p+0L : 0xd.a8263394be6d0e58c1c35a8a3bap-8L : inexact-ok
|
||||
= cos upward ldbl-128 0x1.8475e6p+0L : 0xd.a8263394be6d0e58c1c35a8a3ba8p-8L : inexact-ok
|
||||
= cos downward ldbl-128ibm 0x1.8475e6p+0L : 0xd.a8263394be6d0e58c1c35a8a38p-8L : inexact-ok
|
||||
= cos tonearest ldbl-128ibm 0x1.8475e6p+0L : 0xd.a8263394be6d0e58c1c35a8a3cp-8L : inexact-ok
|
||||
= cos towardzero ldbl-128ibm 0x1.8475e6p+0L : 0xd.a8263394be6d0e58c1c35a8a38p-8L : inexact-ok
|
||||
= cos upward ldbl-128ibm 0x1.8475e6p+0L : 0xd.a8263394be6d0e58c1c35a8a3cp-8L : inexact-ok
|
||||
= cos downward flt-32 0x1.8475e4p+0f : 0xd.a8283p-8f : inexact-ok
|
||||
= cos tonearest flt-32 0x1.8475e4p+0f : 0xd.a8283p-8f : inexact-ok
|
||||
= cos towardzero flt-32 0x1.8475e4p+0f : 0xd.a8283p-8f : inexact-ok
|
||||
= cos upward flt-32 0x1.8475e4p+0f : 0xd.a8284p-8f : inexact-ok
|
||||
= cos downward dbl-64 0x1.8475e4p+0 : 0xd.a82832da19f98p-8 : inexact-ok
|
||||
= cos tonearest dbl-64 0x1.8475e4p+0 : 0xd.a82832da19f98p-8 : inexact-ok
|
||||
= cos towardzero dbl-64 0x1.8475e4p+0 : 0xd.a82832da19f98p-8 : inexact-ok
|
||||
= cos upward dbl-64 0x1.8475e4p+0 : 0xd.a82832da19fap-8 : inexact-ok
|
||||
= cos downward ldbl-96-intel 0x1.8475e4p+0L : 0xd.a82832da19f9891p-8L : inexact-ok
|
||||
= cos tonearest ldbl-96-intel 0x1.8475e4p+0L : 0xd.a82832da19f9892p-8L : inexact-ok
|
||||
= cos towardzero ldbl-96-intel 0x1.8475e4p+0L : 0xd.a82832da19f9891p-8L : inexact-ok
|
||||
= cos upward ldbl-96-intel 0x1.8475e4p+0L : 0xd.a82832da19f9892p-8L : inexact-ok
|
||||
= cos downward ldbl-96-m68k 0x1.8475e4p+0L : 0xd.a82832da19f9891p-8L : inexact-ok
|
||||
= cos tonearest ldbl-96-m68k 0x1.8475e4p+0L : 0xd.a82832da19f9892p-8L : inexact-ok
|
||||
= cos towardzero ldbl-96-m68k 0x1.8475e4p+0L : 0xd.a82832da19f9891p-8L : inexact-ok
|
||||
= cos upward ldbl-96-m68k 0x1.8475e4p+0L : 0xd.a82832da19f9892p-8L : inexact-ok
|
||||
= cos downward ldbl-128 0x1.8475e4p+0L : 0xd.a82832da19f9891d9762fa659ff8p-8L : inexact-ok
|
||||
= cos tonearest ldbl-128 0x1.8475e4p+0L : 0xd.a82832da19f9891d9762fa659ff8p-8L : inexact-ok
|
||||
= cos towardzero ldbl-128 0x1.8475e4p+0L : 0xd.a82832da19f9891d9762fa659ff8p-8L : inexact-ok
|
||||
= cos upward ldbl-128 0x1.8475e4p+0L : 0xd.a82832da19f9891d9762fa65ap-8L : inexact-ok
|
||||
= cos downward ldbl-128ibm 0x1.8475e4p+0L : 0xd.a82832da19f9891d9762fa659cp-8L : inexact-ok
|
||||
= cos tonearest ldbl-128ibm 0x1.8475e4p+0L : 0xd.a82832da19f9891d9762fa65ap-8L : inexact-ok
|
||||
= cos towardzero ldbl-128ibm 0x1.8475e4p+0L : 0xd.a82832da19f9891d9762fa659cp-8L : inexact-ok
|
||||
= cos upward ldbl-128ibm 0x1.8475e4p+0L : 0xd.a82832da19f9891d9762fa65ap-8L : inexact-ok
|
||||
= cos downward dbl-64 0x1.8475e5afd4481p+0 : 0xd.a82683a33cbe8p-8 : inexact-ok
|
||||
= cos tonearest dbl-64 0x1.8475e5afd4481p+0 : 0xd.a82683a33cbe8p-8 : inexact-ok
|
||||
= cos towardzero dbl-64 0x1.8475e5afd4481p+0 : 0xd.a82683a33cbe8p-8 : inexact-ok
|
||||
= cos upward dbl-64 0x1.8475e5afd4481p+0 : 0xd.a82683a33cbfp-8 : inexact-ok
|
||||
= cos downward ldbl-96-intel 0x1.8475e5afd4481p+0L : 0xd.a82683a33cbebffp-8L : inexact-ok
|
||||
= cos tonearest ldbl-96-intel 0x1.8475e5afd4481p+0L : 0xd.a82683a33cbecp-8L : inexact-ok
|
||||
= cos towardzero ldbl-96-intel 0x1.8475e5afd4481p+0L : 0xd.a82683a33cbebffp-8L : inexact-ok
|
||||
= cos upward ldbl-96-intel 0x1.8475e5afd4481p+0L : 0xd.a82683a33cbecp-8L : inexact-ok
|
||||
= cos downward ldbl-96-m68k 0x1.8475e5afd4481p+0L : 0xd.a82683a33cbebffp-8L : inexact-ok
|
||||
= cos tonearest ldbl-96-m68k 0x1.8475e5afd4481p+0L : 0xd.a82683a33cbecp-8L : inexact-ok
|
||||
= cos towardzero ldbl-96-m68k 0x1.8475e5afd4481p+0L : 0xd.a82683a33cbebffp-8L : inexact-ok
|
||||
= cos upward ldbl-96-m68k 0x1.8475e5afd4481p+0L : 0xd.a82683a33cbecp-8L : inexact-ok
|
||||
= cos downward ldbl-128 0x1.8475e5afd4481p+0L : 0xd.a82683a33cbebfffffffa2966878p-8L : inexact-ok
|
||||
= cos tonearest ldbl-128 0x1.8475e5afd4481p+0L : 0xd.a82683a33cbebfffffffa2966878p-8L : inexact-ok
|
||||
= cos towardzero ldbl-128 0x1.8475e5afd4481p+0L : 0xd.a82683a33cbebfffffffa2966878p-8L : inexact-ok
|
||||
= cos upward ldbl-128 0x1.8475e5afd4481p+0L : 0xd.a82683a33cbebfffffffa296688p-8L : inexact-ok
|
||||
= cos downward ldbl-128ibm 0x1.8475e5afd4481p+0L : 0xd.a82683a33cbebfffffffa29668p-8L : inexact-ok
|
||||
= cos tonearest ldbl-128ibm 0x1.8475e5afd4481p+0L : 0xd.a82683a33cbebfffffffa29668p-8L : inexact-ok
|
||||
= cos towardzero ldbl-128ibm 0x1.8475e5afd4481p+0L : 0xd.a82683a33cbebfffffffa29668p-8L : inexact-ok
|
||||
= cos upward ldbl-128ibm 0x1.8475e5afd4481p+0L : 0xd.a82683a33cbebfffffffa2966cp-8L : inexact-ok
|
||||
cosh 0
|
||||
= cosh downward flt-32 0x0p+0f : 0x1p+0f : inexact-ok
|
||||
= cosh tonearest flt-32 0x0p+0f : 0x1p+0f : inexact-ok
|
||||
@@ -262073,6 +262142,75 @@ sin -min_subnorm
|
||||
= sin tonearest ldbl-128 -0x4p-16496L : -0x4p-16496L : inexact-ok underflow errno-erange-ok
|
||||
= sin towardzero ldbl-128 -0x4p-16496L : -0x0p+0L : inexact-ok underflow errno-erange-ok
|
||||
= sin upward ldbl-128 -0x4p-16496L : -0x0p+0L : inexact-ok underflow errno-erange-ok
|
||||
sin 0x1.8475e5afd4481p+0
|
||||
= sin downward flt-32 0x1.8475e6p+0f : 0xf.fa2adp-4f : inexact-ok
|
||||
= sin tonearest flt-32 0x1.8475e6p+0f : 0xf.fa2aep-4f : inexact-ok
|
||||
= sin towardzero flt-32 0x1.8475e6p+0f : 0xf.fa2adp-4f : inexact-ok
|
||||
= sin upward flt-32 0x1.8475e6p+0f : 0xf.fa2aep-4f : inexact-ok
|
||||
= sin downward dbl-64 0x1.8475e6p+0 : 0xf.fa2add3e58948p-4 : inexact-ok
|
||||
= sin tonearest dbl-64 0x1.8475e6p+0 : 0xf.fa2add3e58948p-4 : inexact-ok
|
||||
= sin towardzero dbl-64 0x1.8475e6p+0 : 0xf.fa2add3e58948p-4 : inexact-ok
|
||||
= sin upward dbl-64 0x1.8475e6p+0 : 0xf.fa2add3e5895p-4 : inexact-ok
|
||||
= sin downward ldbl-96-intel 0x1.8475e6p+0L : 0xf.fa2add3e58948d1p-4L : inexact-ok
|
||||
= sin tonearest ldbl-96-intel 0x1.8475e6p+0L : 0xf.fa2add3e58948d1p-4L : inexact-ok
|
||||
= sin towardzero ldbl-96-intel 0x1.8475e6p+0L : 0xf.fa2add3e58948d1p-4L : inexact-ok
|
||||
= sin upward ldbl-96-intel 0x1.8475e6p+0L : 0xf.fa2add3e58948d2p-4L : inexact-ok
|
||||
= sin downward ldbl-96-m68k 0x1.8475e6p+0L : 0xf.fa2add3e58948d1p-4L : inexact-ok
|
||||
= sin tonearest ldbl-96-m68k 0x1.8475e6p+0L : 0xf.fa2add3e58948d1p-4L : inexact-ok
|
||||
= sin towardzero ldbl-96-m68k 0x1.8475e6p+0L : 0xf.fa2add3e58948d1p-4L : inexact-ok
|
||||
= sin upward ldbl-96-m68k 0x1.8475e6p+0L : 0xf.fa2add3e58948d2p-4L : inexact-ok
|
||||
= sin downward ldbl-128 0x1.8475e6p+0L : 0xf.fa2add3e58948d10238cc27b5618p-4L : inexact-ok
|
||||
= sin tonearest ldbl-128 0x1.8475e6p+0L : 0xf.fa2add3e58948d10238cc27b562p-4L : inexact-ok
|
||||
= sin towardzero ldbl-128 0x1.8475e6p+0L : 0xf.fa2add3e58948d10238cc27b5618p-4L : inexact-ok
|
||||
= sin upward ldbl-128 0x1.8475e6p+0L : 0xf.fa2add3e58948d10238cc27b562p-4L : inexact-ok
|
||||
= sin downward ldbl-128ibm 0x1.8475e6p+0L : 0xf.fa2add3e58948d10238cc27b54p-4L : inexact-ok
|
||||
= sin tonearest ldbl-128ibm 0x1.8475e6p+0L : 0xf.fa2add3e58948d10238cc27b58p-4L : inexact-ok
|
||||
= sin towardzero ldbl-128ibm 0x1.8475e6p+0L : 0xf.fa2add3e58948d10238cc27b54p-4L : inexact-ok
|
||||
= sin upward ldbl-128ibm 0x1.8475e6p+0L : 0xf.fa2add3e58948d10238cc27b58p-4L : inexact-ok
|
||||
= sin downward flt-32 0x1.8475e4p+0f : 0xf.fa2adp-4f : inexact-ok
|
||||
= sin tonearest flt-32 0x1.8475e4p+0f : 0xf.fa2aep-4f : inexact-ok
|
||||
= sin towardzero flt-32 0x1.8475e4p+0f : 0xf.fa2adp-4f : inexact-ok
|
||||
= sin upward flt-32 0x1.8475e4p+0f : 0xf.fa2aep-4f : inexact-ok
|
||||
= sin downward dbl-64 0x1.8475e4p+0 : 0xf.fa2adb8953aep-4 : inexact-ok
|
||||
= sin tonearest dbl-64 0x1.8475e4p+0 : 0xf.fa2adb8953aep-4 : inexact-ok
|
||||
= sin towardzero dbl-64 0x1.8475e4p+0 : 0xf.fa2adb8953aep-4 : inexact-ok
|
||||
= sin upward dbl-64 0x1.8475e4p+0 : 0xf.fa2adb8953ae8p-4 : inexact-ok
|
||||
= sin downward ldbl-96-intel 0x1.8475e4p+0L : 0xf.fa2adb8953ae262p-4L : inexact-ok
|
||||
= sin tonearest ldbl-96-intel 0x1.8475e4p+0L : 0xf.fa2adb8953ae262p-4L : inexact-ok
|
||||
= sin towardzero ldbl-96-intel 0x1.8475e4p+0L : 0xf.fa2adb8953ae262p-4L : inexact-ok
|
||||
= sin upward ldbl-96-intel 0x1.8475e4p+0L : 0xf.fa2adb8953ae263p-4L : inexact-ok
|
||||
= sin downward ldbl-96-m68k 0x1.8475e4p+0L : 0xf.fa2adb8953ae262p-4L : inexact-ok
|
||||
= sin tonearest ldbl-96-m68k 0x1.8475e4p+0L : 0xf.fa2adb8953ae262p-4L : inexact-ok
|
||||
= sin towardzero ldbl-96-m68k 0x1.8475e4p+0L : 0xf.fa2adb8953ae262p-4L : inexact-ok
|
||||
= sin upward ldbl-96-m68k 0x1.8475e4p+0L : 0xf.fa2adb8953ae263p-4L : inexact-ok
|
||||
= sin downward ldbl-128 0x1.8475e4p+0L : 0xf.fa2adb8953ae26229c919ec8f6b8p-4L : inexact-ok
|
||||
= sin tonearest ldbl-128 0x1.8475e4p+0L : 0xf.fa2adb8953ae26229c919ec8f6cp-4L : inexact-ok
|
||||
= sin towardzero ldbl-128 0x1.8475e4p+0L : 0xf.fa2adb8953ae26229c919ec8f6b8p-4L : inexact-ok
|
||||
= sin upward ldbl-128 0x1.8475e4p+0L : 0xf.fa2adb8953ae26229c919ec8f6cp-4L : inexact-ok
|
||||
= sin downward ldbl-128ibm 0x1.8475e4p+0L : 0xf.fa2adb8953ae26229c919ec8f4p-4L : inexact-ok
|
||||
= sin tonearest ldbl-128ibm 0x1.8475e4p+0L : 0xf.fa2adb8953ae26229c919ec8f8p-4L : inexact-ok
|
||||
= sin towardzero ldbl-128ibm 0x1.8475e4p+0L : 0xf.fa2adb8953ae26229c919ec8f4p-4L : inexact-ok
|
||||
= sin upward ldbl-128ibm 0x1.8475e4p+0L : 0xf.fa2adb8953ae26229c919ec8f8p-4L : inexact-ok
|
||||
= sin downward dbl-64 0x1.8475e5afd4481p+0 : 0xf.fa2adcf9ea838p-4 : inexact-ok
|
||||
= sin tonearest dbl-64 0x1.8475e5afd4481p+0 : 0xf.fa2adcf9ea84p-4 : inexact-ok
|
||||
= sin towardzero dbl-64 0x1.8475e5afd4481p+0 : 0xf.fa2adcf9ea838p-4 : inexact-ok
|
||||
= sin upward dbl-64 0x1.8475e5afd4481p+0 : 0xf.fa2adcf9ea84p-4 : inexact-ok
|
||||
= sin downward ldbl-96-intel 0x1.8475e5afd4481p+0L : 0xf.fa2adcf9ea83dbdp-4L : inexact-ok
|
||||
= sin tonearest ldbl-96-intel 0x1.8475e5afd4481p+0L : 0xf.fa2adcf9ea83dbep-4L : inexact-ok
|
||||
= sin towardzero ldbl-96-intel 0x1.8475e5afd4481p+0L : 0xf.fa2adcf9ea83dbdp-4L : inexact-ok
|
||||
= sin upward ldbl-96-intel 0x1.8475e5afd4481p+0L : 0xf.fa2adcf9ea83dbep-4L : inexact-ok
|
||||
= sin downward ldbl-96-m68k 0x1.8475e5afd4481p+0L : 0xf.fa2adcf9ea83dbdp-4L : inexact-ok
|
||||
= sin tonearest ldbl-96-m68k 0x1.8475e5afd4481p+0L : 0xf.fa2adcf9ea83dbep-4L : inexact-ok
|
||||
= sin towardzero ldbl-96-m68k 0x1.8475e5afd4481p+0L : 0xf.fa2adcf9ea83dbdp-4L : inexact-ok
|
||||
= sin upward ldbl-96-m68k 0x1.8475e5afd4481p+0L : 0xf.fa2adcf9ea83dbep-4L : inexact-ok
|
||||
= sin downward ldbl-128 0x1.8475e5afd4481p+0L : 0xf.fa2adcf9ea83dbdd053ee455ea68p-4L : inexact-ok
|
||||
= sin tonearest ldbl-128 0x1.8475e5afd4481p+0L : 0xf.fa2adcf9ea83dbdd053ee455ea7p-4L : inexact-ok
|
||||
= sin towardzero ldbl-128 0x1.8475e5afd4481p+0L : 0xf.fa2adcf9ea83dbdd053ee455ea68p-4L : inexact-ok
|
||||
= sin upward ldbl-128 0x1.8475e5afd4481p+0L : 0xf.fa2adcf9ea83dbdd053ee455ea7p-4L : inexact-ok
|
||||
= sin downward ldbl-128ibm 0x1.8475e5afd4481p+0L : 0xf.fa2adcf9ea83dbdd053ee455e8p-4L : inexact-ok
|
||||
= sin tonearest ldbl-128ibm 0x1.8475e5afd4481p+0L : 0xf.fa2adcf9ea83dbdd053ee455ecp-4L : inexact-ok
|
||||
= sin towardzero ldbl-128ibm 0x1.8475e5afd4481p+0L : 0xf.fa2adcf9ea83dbdd053ee455e8p-4L : inexact-ok
|
||||
= sin upward ldbl-128ibm 0x1.8475e5afd4481p+0L : 0xf.fa2adcf9ea83dbdd053ee455ecp-4L : inexact-ok
|
||||
sincos 0
|
||||
= sincos downward flt-32 0x0p+0f : 0x0p+0f 0x1p+0f : inexact-ok
|
||||
= sincos tonearest flt-32 0x0p+0f : 0x0p+0f 0x1p+0f : inexact-ok
|
||||
@@ -264170,6 +264308,75 @@ sincos -min_subnorm
|
||||
= sincos tonearest ldbl-128 -0x4p-16496L : -0x4p-16496L 0x1p+0L : inexact-ok underflow errno-erange-ok
|
||||
= sincos towardzero ldbl-128 -0x4p-16496L : -0x0p+0L 0xf.fffffffffffffffffffffffffff8p-4L : inexact-ok underflow errno-erange-ok
|
||||
= sincos upward ldbl-128 -0x4p-16496L : -0x0p+0L 0x1p+0L : inexact-ok underflow errno-erange-ok
|
||||
sincos 0x1.8475e5afd4481p+0
|
||||
= sincos downward flt-32 0x1.8475e6p+0f : 0xf.fa2adp-4f 0xd.a8263p-8f : inexact-ok
|
||||
= sincos tonearest flt-32 0x1.8475e6p+0f : 0xf.fa2aep-4f 0xd.a8263p-8f : inexact-ok
|
||||
= sincos towardzero flt-32 0x1.8475e6p+0f : 0xf.fa2adp-4f 0xd.a8263p-8f : inexact-ok
|
||||
= sincos upward flt-32 0x1.8475e6p+0f : 0xf.fa2aep-4f 0xd.a8264p-8f : inexact-ok
|
||||
= sincos downward dbl-64 0x1.8475e6p+0 : 0xf.fa2add3e58948p-4 0xd.a8263394be6dp-8 : inexact-ok
|
||||
= sincos tonearest dbl-64 0x1.8475e6p+0 : 0xf.fa2add3e58948p-4 0xd.a8263394be6dp-8 : inexact-ok
|
||||
= sincos towardzero dbl-64 0x1.8475e6p+0 : 0xf.fa2add3e58948p-4 0xd.a8263394be6dp-8 : inexact-ok
|
||||
= sincos upward dbl-64 0x1.8475e6p+0 : 0xf.fa2add3e5895p-4 0xd.a8263394be6d8p-8 : inexact-ok
|
||||
= sincos downward ldbl-96-intel 0x1.8475e6p+0L : 0xf.fa2add3e58948d1p-4L 0xd.a8263394be6d0e5p-8L : inexact-ok
|
||||
= sincos tonearest ldbl-96-intel 0x1.8475e6p+0L : 0xf.fa2add3e58948d1p-4L 0xd.a8263394be6d0e6p-8L : inexact-ok
|
||||
= sincos towardzero ldbl-96-intel 0x1.8475e6p+0L : 0xf.fa2add3e58948d1p-4L 0xd.a8263394be6d0e5p-8L : inexact-ok
|
||||
= sincos upward ldbl-96-intel 0x1.8475e6p+0L : 0xf.fa2add3e58948d2p-4L 0xd.a8263394be6d0e6p-8L : inexact-ok
|
||||
= sincos downward ldbl-96-m68k 0x1.8475e6p+0L : 0xf.fa2add3e58948d1p-4L 0xd.a8263394be6d0e5p-8L : inexact-ok
|
||||
= sincos tonearest ldbl-96-m68k 0x1.8475e6p+0L : 0xf.fa2add3e58948d1p-4L 0xd.a8263394be6d0e6p-8L : inexact-ok
|
||||
= sincos towardzero ldbl-96-m68k 0x1.8475e6p+0L : 0xf.fa2add3e58948d1p-4L 0xd.a8263394be6d0e5p-8L : inexact-ok
|
||||
= sincos upward ldbl-96-m68k 0x1.8475e6p+0L : 0xf.fa2add3e58948d2p-4L 0xd.a8263394be6d0e6p-8L : inexact-ok
|
||||
= sincos downward ldbl-128 0x1.8475e6p+0L : 0xf.fa2add3e58948d10238cc27b5618p-4L 0xd.a8263394be6d0e58c1c35a8a3bap-8L : inexact-ok
|
||||
= sincos tonearest ldbl-128 0x1.8475e6p+0L : 0xf.fa2add3e58948d10238cc27b562p-4L 0xd.a8263394be6d0e58c1c35a8a3bap-8L : inexact-ok
|
||||
= sincos towardzero ldbl-128 0x1.8475e6p+0L : 0xf.fa2add3e58948d10238cc27b5618p-4L 0xd.a8263394be6d0e58c1c35a8a3bap-8L : inexact-ok
|
||||
= sincos upward ldbl-128 0x1.8475e6p+0L : 0xf.fa2add3e58948d10238cc27b562p-4L 0xd.a8263394be6d0e58c1c35a8a3ba8p-8L : inexact-ok
|
||||
= sincos downward ldbl-128ibm 0x1.8475e6p+0L : 0xf.fa2add3e58948d10238cc27b54p-4L 0xd.a8263394be6d0e58c1c35a8a38p-8L : inexact-ok
|
||||
= sincos tonearest ldbl-128ibm 0x1.8475e6p+0L : 0xf.fa2add3e58948d10238cc27b58p-4L 0xd.a8263394be6d0e58c1c35a8a3cp-8L : inexact-ok
|
||||
= sincos towardzero ldbl-128ibm 0x1.8475e6p+0L : 0xf.fa2add3e58948d10238cc27b54p-4L 0xd.a8263394be6d0e58c1c35a8a38p-8L : inexact-ok
|
||||
= sincos upward ldbl-128ibm 0x1.8475e6p+0L : 0xf.fa2add3e58948d10238cc27b58p-4L 0xd.a8263394be6d0e58c1c35a8a3cp-8L : inexact-ok
|
||||
= sincos downward flt-32 0x1.8475e4p+0f : 0xf.fa2adp-4f 0xd.a8283p-8f : inexact-ok
|
||||
= sincos tonearest flt-32 0x1.8475e4p+0f : 0xf.fa2aep-4f 0xd.a8283p-8f : inexact-ok
|
||||
= sincos towardzero flt-32 0x1.8475e4p+0f : 0xf.fa2adp-4f 0xd.a8283p-8f : inexact-ok
|
||||
= sincos upward flt-32 0x1.8475e4p+0f : 0xf.fa2aep-4f 0xd.a8284p-8f : inexact-ok
|
||||
= sincos downward dbl-64 0x1.8475e4p+0 : 0xf.fa2adb8953aep-4 0xd.a82832da19f98p-8 : inexact-ok
|
||||
= sincos tonearest dbl-64 0x1.8475e4p+0 : 0xf.fa2adb8953aep-4 0xd.a82832da19f98p-8 : inexact-ok
|
||||
= sincos towardzero dbl-64 0x1.8475e4p+0 : 0xf.fa2adb8953aep-4 0xd.a82832da19f98p-8 : inexact-ok
|
||||
= sincos upward dbl-64 0x1.8475e4p+0 : 0xf.fa2adb8953ae8p-4 0xd.a82832da19fap-8 : inexact-ok
|
||||
= sincos downward ldbl-96-intel 0x1.8475e4p+0L : 0xf.fa2adb8953ae262p-4L 0xd.a82832da19f9891p-8L : inexact-ok
|
||||
= sincos tonearest ldbl-96-intel 0x1.8475e4p+0L : 0xf.fa2adb8953ae262p-4L 0xd.a82832da19f9892p-8L : inexact-ok
|
||||
= sincos towardzero ldbl-96-intel 0x1.8475e4p+0L : 0xf.fa2adb8953ae262p-4L 0xd.a82832da19f9891p-8L : inexact-ok
|
||||
= sincos upward ldbl-96-intel 0x1.8475e4p+0L : 0xf.fa2adb8953ae263p-4L 0xd.a82832da19f9892p-8L : inexact-ok
|
||||
= sincos downward ldbl-96-m68k 0x1.8475e4p+0L : 0xf.fa2adb8953ae262p-4L 0xd.a82832da19f9891p-8L : inexact-ok
|
||||
= sincos tonearest ldbl-96-m68k 0x1.8475e4p+0L : 0xf.fa2adb8953ae262p-4L 0xd.a82832da19f9892p-8L : inexact-ok
|
||||
= sincos towardzero ldbl-96-m68k 0x1.8475e4p+0L : 0xf.fa2adb8953ae262p-4L 0xd.a82832da19f9891p-8L : inexact-ok
|
||||
= sincos upward ldbl-96-m68k 0x1.8475e4p+0L : 0xf.fa2adb8953ae263p-4L 0xd.a82832da19f9892p-8L : inexact-ok
|
||||
= sincos downward ldbl-128 0x1.8475e4p+0L : 0xf.fa2adb8953ae26229c919ec8f6b8p-4L 0xd.a82832da19f9891d9762fa659ff8p-8L : inexact-ok
|
||||
= sincos tonearest ldbl-128 0x1.8475e4p+0L : 0xf.fa2adb8953ae26229c919ec8f6cp-4L 0xd.a82832da19f9891d9762fa659ff8p-8L : inexact-ok
|
||||
= sincos towardzero ldbl-128 0x1.8475e4p+0L : 0xf.fa2adb8953ae26229c919ec8f6b8p-4L 0xd.a82832da19f9891d9762fa659ff8p-8L : inexact-ok
|
||||
= sincos upward ldbl-128 0x1.8475e4p+0L : 0xf.fa2adb8953ae26229c919ec8f6cp-4L 0xd.a82832da19f9891d9762fa65ap-8L : inexact-ok
|
||||
= sincos downward ldbl-128ibm 0x1.8475e4p+0L : 0xf.fa2adb8953ae26229c919ec8f4p-4L 0xd.a82832da19f9891d9762fa659cp-8L : inexact-ok
|
||||
= sincos tonearest ldbl-128ibm 0x1.8475e4p+0L : 0xf.fa2adb8953ae26229c919ec8f8p-4L 0xd.a82832da19f9891d9762fa65ap-8L : inexact-ok
|
||||
= sincos towardzero ldbl-128ibm 0x1.8475e4p+0L : 0xf.fa2adb8953ae26229c919ec8f4p-4L 0xd.a82832da19f9891d9762fa659cp-8L : inexact-ok
|
||||
= sincos upward ldbl-128ibm 0x1.8475e4p+0L : 0xf.fa2adb8953ae26229c919ec8f8p-4L 0xd.a82832da19f9891d9762fa65ap-8L : inexact-ok
|
||||
= sincos downward dbl-64 0x1.8475e5afd4481p+0 : 0xf.fa2adcf9ea838p-4 0xd.a82683a33cbe8p-8 : inexact-ok
|
||||
= sincos tonearest dbl-64 0x1.8475e5afd4481p+0 : 0xf.fa2adcf9ea84p-4 0xd.a82683a33cbe8p-8 : inexact-ok
|
||||
= sincos towardzero dbl-64 0x1.8475e5afd4481p+0 : 0xf.fa2adcf9ea838p-4 0xd.a82683a33cbe8p-8 : inexact-ok
|
||||
= sincos upward dbl-64 0x1.8475e5afd4481p+0 : 0xf.fa2adcf9ea84p-4 0xd.a82683a33cbfp-8 : inexact-ok
|
||||
= sincos downward ldbl-96-intel 0x1.8475e5afd4481p+0L : 0xf.fa2adcf9ea83dbdp-4L 0xd.a82683a33cbebffp-8L : inexact-ok
|
||||
= sincos tonearest ldbl-96-intel 0x1.8475e5afd4481p+0L : 0xf.fa2adcf9ea83dbep-4L 0xd.a82683a33cbecp-8L : inexact-ok
|
||||
= sincos towardzero ldbl-96-intel 0x1.8475e5afd4481p+0L : 0xf.fa2adcf9ea83dbdp-4L 0xd.a82683a33cbebffp-8L : inexact-ok
|
||||
= sincos upward ldbl-96-intel 0x1.8475e5afd4481p+0L : 0xf.fa2adcf9ea83dbep-4L 0xd.a82683a33cbecp-8L : inexact-ok
|
||||
= sincos downward ldbl-96-m68k 0x1.8475e5afd4481p+0L : 0xf.fa2adcf9ea83dbdp-4L 0xd.a82683a33cbebffp-8L : inexact-ok
|
||||
= sincos tonearest ldbl-96-m68k 0x1.8475e5afd4481p+0L : 0xf.fa2adcf9ea83dbep-4L 0xd.a82683a33cbecp-8L : inexact-ok
|
||||
= sincos towardzero ldbl-96-m68k 0x1.8475e5afd4481p+0L : 0xf.fa2adcf9ea83dbdp-4L 0xd.a82683a33cbebffp-8L : inexact-ok
|
||||
= sincos upward ldbl-96-m68k 0x1.8475e5afd4481p+0L : 0xf.fa2adcf9ea83dbep-4L 0xd.a82683a33cbecp-8L : inexact-ok
|
||||
= sincos downward ldbl-128 0x1.8475e5afd4481p+0L : 0xf.fa2adcf9ea83dbdd053ee455ea68p-4L 0xd.a82683a33cbebfffffffa2966878p-8L : inexact-ok
|
||||
= sincos tonearest ldbl-128 0x1.8475e5afd4481p+0L : 0xf.fa2adcf9ea83dbdd053ee455ea7p-4L 0xd.a82683a33cbebfffffffa2966878p-8L : inexact-ok
|
||||
= sincos towardzero ldbl-128 0x1.8475e5afd4481p+0L : 0xf.fa2adcf9ea83dbdd053ee455ea68p-4L 0xd.a82683a33cbebfffffffa2966878p-8L : inexact-ok
|
||||
= sincos upward ldbl-128 0x1.8475e5afd4481p+0L : 0xf.fa2adcf9ea83dbdd053ee455ea7p-4L 0xd.a82683a33cbebfffffffa296688p-8L : inexact-ok
|
||||
= sincos downward ldbl-128ibm 0x1.8475e5afd4481p+0L : 0xf.fa2adcf9ea83dbdd053ee455e8p-4L 0xd.a82683a33cbebfffffffa29668p-8L : inexact-ok
|
||||
= sincos tonearest ldbl-128ibm 0x1.8475e5afd4481p+0L : 0xf.fa2adcf9ea83dbdd053ee455ecp-4L 0xd.a82683a33cbebfffffffa29668p-8L : inexact-ok
|
||||
= sincos towardzero ldbl-128ibm 0x1.8475e5afd4481p+0L : 0xf.fa2adcf9ea83dbdd053ee455e8p-4L 0xd.a82683a33cbebfffffffa29668p-8L : inexact-ok
|
||||
= sincos upward ldbl-128ibm 0x1.8475e5afd4481p+0L : 0xf.fa2adcf9ea83dbdd053ee455ecp-4L 0xd.a82683a33cbebfffffffa2966cp-8L : inexact-ok
|
||||
sinh 0
|
||||
= sinh downward flt-32 0x0p+0f : 0x0p+0f : inexact-ok
|
||||
= sinh tonearest flt-32 0x0p+0f : 0x0p+0f : inexact-ok
|
||||
|
||||
@@ -30,12 +30,17 @@ do_test (void)
|
||||
header fix this test will not compile. */
|
||||
if (isinff (1.0f)
|
||||
|| !isinff (INFINITY)
|
||||
#ifndef NO_LONG_DOUBLE
|
||||
|| isinfl (1.0L)
|
||||
|| !isinfl (INFINITY)
|
||||
#endif
|
||||
|| isnanf (2.0f)
|
||||
|| !isnanf (NAN)
|
||||
#ifndef NO_LONG_DOUBLE
|
||||
|| isnanl (2.0L)
|
||||
|| !isnanl (NAN))
|
||||
|| !isnanl (NAN)
|
||||
#endif
|
||||
)
|
||||
{
|
||||
printf ("FAIL: Failed to call is* functions.\n");
|
||||
exit (1);
|
||||
|
||||
+11
-9
@@ -680,16 +680,18 @@ nis_server_cache_add (const_nis_name name, int search_parent,
|
||||
/* Choose which entry should be evicted from the cache. */
|
||||
loc = &nis_server_cache[0];
|
||||
if (*loc != NULL)
|
||||
for (i = 1; i < 16; ++i)
|
||||
if (nis_server_cache[i] == NULL)
|
||||
{
|
||||
{
|
||||
for (i = 1; i < 16; ++i)
|
||||
if (nis_server_cache[i] == NULL)
|
||||
{
|
||||
loc = &nis_server_cache[i];
|
||||
break;
|
||||
}
|
||||
else if ((*loc)->uses > nis_server_cache[i]->uses
|
||||
|| ((*loc)->uses == nis_server_cache[i]->uses
|
||||
&& (*loc)->expires > nis_server_cache[i]->expires))
|
||||
loc = &nis_server_cache[i];
|
||||
break;
|
||||
}
|
||||
else if ((*loc)->uses > nis_server_cache[i]->uses
|
||||
|| ((*loc)->uses == nis_server_cache[i]->uses
|
||||
&& (*loc)->expires > nis_server_cache[i]->expires))
|
||||
loc = &nis_server_cache[i];
|
||||
}
|
||||
old = *loc;
|
||||
*loc = new;
|
||||
|
||||
|
||||
@@ -266,7 +266,7 @@ _nss_nis_initgroups_dyn (const char *user, gid_t group, long int *start,
|
||||
|
||||
tmpbuf = __alloca (buflen);
|
||||
|
||||
do
|
||||
while (1)
|
||||
{
|
||||
while ((status =
|
||||
internal_getgrent_r (&grpbuf, tmpbuf, buflen, errnop,
|
||||
@@ -275,8 +275,11 @@ _nss_nis_initgroups_dyn (const char *user, gid_t group, long int *start,
|
||||
tmpbuf = extend_alloca (tmpbuf, buflen, 2 * buflen);
|
||||
|
||||
if (status != NSS_STATUS_SUCCESS)
|
||||
goto done;
|
||||
|
||||
{
|
||||
if (status == NSS_STATUS_NOTFOUND)
|
||||
status = NSS_STATUS_SUCCESS;
|
||||
goto done;
|
||||
}
|
||||
|
||||
g = &grpbuf;
|
||||
if (g->gr_gid != group)
|
||||
@@ -304,7 +307,11 @@ _nss_nis_initgroups_dyn (const char *user, gid_t group, long int *start,
|
||||
|
||||
newgroups = realloc (groups, newsize * sizeof (*groups));
|
||||
if (newgroups == NULL)
|
||||
goto done;
|
||||
{
|
||||
status = NSS_STATUS_TRYAGAIN;
|
||||
*errnop = errno;
|
||||
goto done;
|
||||
}
|
||||
*groupsp = groups = newgroups;
|
||||
*size = newsize;
|
||||
}
|
||||
@@ -316,7 +323,6 @@ _nss_nis_initgroups_dyn (const char *user, gid_t group, long int *start,
|
||||
}
|
||||
}
|
||||
}
|
||||
while (status == NSS_STATUS_SUCCESS);
|
||||
|
||||
done:
|
||||
while (intern.start != NULL)
|
||||
|
||||
+6
-2
@@ -319,8 +319,8 @@ tests += tst-cancelx2 tst-cancelx3 tst-cancelx4 tst-cancelx5 \
|
||||
tst-cleanupx0 tst-cleanupx1 tst-cleanupx2 tst-cleanupx3 tst-cleanupx4 \
|
||||
tst-oncex3 tst-oncex4
|
||||
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
|
||||
@@ -525,6 +525,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
|
||||
|
||||
|
||||
@@ -245,9 +245,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. */
|
||||
|
||||
+2
-9
@@ -48,14 +48,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. */
|
||||
@@ -328,7 +322,7 @@ __pthread_initialize_minimal_internal (void)
|
||||
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));
|
||||
@@ -336,8 +330,7 @@ __pthread_initialize_minimal_internal (void)
|
||||
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 ();
|
||||
__set_robust_list_avail = -1;
|
||||
}
|
||||
|
||||
#ifdef __NR_futex
|
||||
|
||||
+10
-33
@@ -25,48 +25,25 @@
|
||||
the historical ABI requires it. For static linking, there is no need to
|
||||
provide anything here--the libc version will be linked in. For shared
|
||||
library ABI compatibility, there must be __fork and fork symbols in
|
||||
libpthread.so; so we define them using IFUNC to redirect to the libc
|
||||
function. */
|
||||
libpthread.so.
|
||||
|
||||
With an IFUNC resolver, it would be possible to avoid the
|
||||
indirection, but the IFUNC resolver might run before the
|
||||
__libc_fork symbol has been relocated, in which case the IFUNC
|
||||
resolver would not be able to provide the correct address. */
|
||||
|
||||
#if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_22)
|
||||
|
||||
# if HAVE_IFUNC
|
||||
|
||||
static __typeof (fork) *
|
||||
__attribute__ ((used))
|
||||
fork_resolve (void)
|
||||
{
|
||||
return &__libc_fork;
|
||||
}
|
||||
|
||||
# ifdef HAVE_ASM_SET_DIRECTIVE
|
||||
# define DEFINE_FORK(name) \
|
||||
asm (".set " #name ", fork_resolve\n" \
|
||||
".globl " #name "\n" \
|
||||
".type " #name ", %gnu_indirect_function");
|
||||
# else
|
||||
# define DEFINE_FORK(name) \
|
||||
asm (#name " = fork_resolve\n" \
|
||||
".globl " #name "\n" \
|
||||
".type " #name ", %gnu_indirect_function");
|
||||
# endif
|
||||
|
||||
# else /* !HAVE_IFUNC */
|
||||
|
||||
static pid_t __attribute__ ((used))
|
||||
fork_compat (void)
|
||||
{
|
||||
return __libc_fork ();
|
||||
}
|
||||
|
||||
# define DEFINE_FORK(name) strong_alias (fork_compat, name)
|
||||
strong_alias (fork_compat, fork_alias)
|
||||
compat_symbol (libpthread, fork_alias, fork, GLIBC_2_0);
|
||||
|
||||
# endif /* HAVE_IFUNC */
|
||||
|
||||
DEFINE_FORK (fork_ifunc)
|
||||
compat_symbol (libpthread, fork_ifunc, fork, GLIBC_2_0);
|
||||
|
||||
DEFINE_FORK (__fork_ifunc)
|
||||
compat_symbol (libpthread, __fork_ifunc, __fork, GLIBC_2_0);
|
||||
strong_alias (fork_compat, __fork_alias)
|
||||
compat_symbol (libpthread, __fork_alias, __fork, GLIBC_2_0);
|
||||
|
||||
#endif
|
||||
|
||||
+14
-11
@@ -199,10 +199,8 @@ hidden_proto (__pthread_keys)
|
||||
/* Number of threads running. */
|
||||
extern unsigned int __nptl_nthreads attribute_hidden;
|
||||
|
||||
#ifndef __ASSUME_SET_ROBUST_LIST
|
||||
/* Negative if we do not have the system call and we can use it. */
|
||||
extern int __set_robust_list_avail attribute_hidden;
|
||||
#endif
|
||||
|
||||
/* Thread Priority Protection. */
|
||||
extern int __sched_fifo_min_prio attribute_hidden;
|
||||
@@ -587,17 +585,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
|
||||
|
||||
@@ -60,9 +60,8 @@ __pthread_cond_broadcast (pthread_cond_t *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,
|
||||
|
||||
@@ -46,11 +46,10 @@ __pthread_cond_signal (pthread_cond_t *cond)
|
||||
++cond->__data.__wakeup_seq;
|
||||
++cond->__data.__futex;
|
||||
|
||||
#if (defined lll_futex_cmp_requeue_pi \
|
||||
&& defined __ASSUME_REQUEUE_PI)
|
||||
#ifdef lll_futex_cmp_requeue_pi
|
||||
pthread_mutex_t *mut = cond->__data.__mutex;
|
||||
|
||||
if (USE_REQUEUE_PI (mut)
|
||||
if (use_requeue_pi (mut)
|
||||
/* This can only really fail with a ENOSYS, since nobody can modify
|
||||
futex while we have the cond_lock. */
|
||||
&& lll_futex_cmp_requeue_pi (&cond->__data.__futex, 1, 0,
|
||||
|
||||
@@ -63,8 +63,7 @@ __pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex,
|
||||
int pshared = (cond->__data.__mutex == (void *) ~0l)
|
||||
? LLL_SHARED : LLL_PRIVATE;
|
||||
|
||||
#if (defined lll_futex_timed_wait_requeue_pi \
|
||||
&& defined __ASSUME_REQUEUE_PI)
|
||||
#ifdef lll_futex_timed_wait_requeue_pi
|
||||
int pi_flag = 0;
|
||||
#endif
|
||||
|
||||
@@ -161,8 +160,7 @@ __pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex,
|
||||
|
||||
/* REQUEUE_PI was implemented after FUTEX_CLOCK_REALTIME, so it is sufficient
|
||||
to check just the former. */
|
||||
#if (defined lll_futex_timed_wait_requeue_pi \
|
||||
&& defined __ASSUME_REQUEUE_PI)
|
||||
#ifdef lll_futex_timed_wait_requeue_pi
|
||||
/* If pi_flag remained 1 then it means that we had the lock and the mutex
|
||||
but a spurious waker raced ahead of us. Give back the mutex before
|
||||
going into wait again. */
|
||||
@@ -171,7 +169,7 @@ __pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex,
|
||||
__pthread_mutex_cond_lock_adjust (mutex);
|
||||
__pthread_mutex_unlock_usercnt (mutex, 0);
|
||||
}
|
||||
pi_flag = USE_REQUEUE_PI (mutex);
|
||||
pi_flag = use_requeue_pi (mutex);
|
||||
|
||||
if (pi_flag)
|
||||
{
|
||||
@@ -250,8 +248,7 @@ __pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex,
|
||||
__pthread_cleanup_pop (&buffer, 0);
|
||||
|
||||
/* Get the mutex before returning. */
|
||||
#if (defined lll_futex_timed_wait_requeue_pi \
|
||||
&& defined __ASSUME_REQUEUE_PI)
|
||||
#ifdef lll_futex_timed_wait_requeue_pi
|
||||
if (pi_flag)
|
||||
{
|
||||
__pthread_mutex_cond_lock_adjust (mutex);
|
||||
|
||||
@@ -86,7 +86,7 @@ __condvar_cleanup (void *arg)
|
||||
|
||||
/* Get the mutex before returning unless asynchronous cancellation
|
||||
is in effect. We don't try to get the mutex if we already own it. */
|
||||
if (!(USE_REQUEUE_PI (cbuffer->mutex))
|
||||
if (!(use_requeue_pi (cbuffer->mutex))
|
||||
|| ((cbuffer->mutex->__data.__lock & FUTEX_TID_MASK)
|
||||
!= THREAD_GETMEM (THREAD_SELF, tid)))
|
||||
{
|
||||
@@ -106,8 +106,7 @@ __pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)
|
||||
int pshared = (cond->__data.__mutex == (void *) ~0l)
|
||||
? LLL_SHARED : LLL_PRIVATE;
|
||||
|
||||
#if (defined lll_futex_wait_requeue_pi \
|
||||
&& defined __ASSUME_REQUEUE_PI)
|
||||
#ifdef lll_futex_wait_requeue_pi
|
||||
int pi_flag = 0;
|
||||
#endif
|
||||
|
||||
@@ -160,8 +159,7 @@ __pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)
|
||||
/* Enable asynchronous cancellation. Required by the standard. */
|
||||
cbuffer.oldtype = __pthread_enable_asynccancel ();
|
||||
|
||||
#if (defined lll_futex_wait_requeue_pi \
|
||||
&& defined __ASSUME_REQUEUE_PI)
|
||||
#ifdef lll_futex_wait_requeue_pi
|
||||
/* If pi_flag remained 1 then it means that we had the lock and the mutex
|
||||
but a spurious waker raced ahead of us. Give back the mutex before
|
||||
going into wait again. */
|
||||
@@ -170,7 +168,7 @@ __pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)
|
||||
__pthread_mutex_cond_lock_adjust (mutex);
|
||||
__pthread_mutex_unlock_usercnt (mutex, 0);
|
||||
}
|
||||
pi_flag = USE_REQUEUE_PI (mutex);
|
||||
pi_flag = use_requeue_pi (mutex);
|
||||
|
||||
if (pi_flag)
|
||||
{
|
||||
@@ -221,8 +219,7 @@ __pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)
|
||||
__pthread_cleanup_pop (&buffer, 0);
|
||||
|
||||
/* Get the mutex before returning. Not needed for PI. */
|
||||
#if (defined lll_futex_wait_requeue_pi \
|
||||
&& defined __ASSUME_REQUEUE_PI)
|
||||
#ifdef lll_futex_wait_requeue_pi
|
||||
if (pi_flag)
|
||||
{
|
||||
__pthread_mutex_cond_lock_adjust (mutex);
|
||||
|
||||
@@ -271,10 +271,7 @@ START_THREAD_DEFN
|
||||
if (__glibc_unlikely (atomic_exchange_acq (&pd->setxid_futex, 0) == -2))
|
||||
futex_wake (&pd->setxid_futex, 1, FUTEX_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;
|
||||
@@ -419,7 +414,6 @@ START_THREAD_DEFN
|
||||
}
|
||||
while (robust != (void *) &pd->robust_head);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Mark the memory of the stack as usable to the kernel. We free
|
||||
everything except for the space used for the TCB itself. */
|
||||
|
||||
@@ -33,11 +33,11 @@ static const struct pthread_mutexattr default_mutexattr =
|
||||
};
|
||||
|
||||
|
||||
static bool
|
||||
prio_inherit_missing (void)
|
||||
bool
|
||||
attribute_hidden
|
||||
__prio_inherit_missing (void)
|
||||
{
|
||||
#ifdef __NR_futex
|
||||
# ifndef __ASSUME_FUTEX_LOCK_PI
|
||||
static int tpi_supported;
|
||||
if (__glibc_unlikely (tpi_supported == 0))
|
||||
{
|
||||
@@ -48,8 +48,6 @@ prio_inherit_missing (void)
|
||||
tpi_supported = INTERNAL_SYSCALL_ERRNO (ret, err) == ENOSYS ? -1 : 1;
|
||||
}
|
||||
return __glibc_unlikely (tpi_supported < 0);
|
||||
# endif
|
||||
return false;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
@@ -75,7 +73,7 @@ __pthread_mutex_init (pthread_mutex_t *mutex,
|
||||
break;
|
||||
|
||||
case PTHREAD_PRIO_INHERIT << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT:
|
||||
if (__glibc_unlikely (prio_inherit_missing ()))
|
||||
if (__glibc_unlikely (__prio_inherit_missing ()))
|
||||
return ENOTSUP;
|
||||
break;
|
||||
|
||||
@@ -94,11 +92,9 @@ __pthread_mutex_init (pthread_mutex_t *mutex,
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -333,6 +333,22 @@ do_test (void)
|
||||
|
||||
puts ("early cancellation succeeded");
|
||||
|
||||
if (ap == &a2)
|
||||
{
|
||||
/* The aio_read(&a) was not canceled because the read request was
|
||||
already in progress. In the meanwhile aio_write(ap) wrote something
|
||||
to the pipe and the read request either has already been finished or
|
||||
is able to read the requested byte.
|
||||
Wait for the read request before returning from this function because
|
||||
the return value and error code from the read syscall will be written
|
||||
to the struct aiocb a, which lies on the stack of this function.
|
||||
Otherwise the stack from subsequent function calls - e.g. _dl_fini -
|
||||
will be corrupted, which can lead to undefined behaviour like a
|
||||
segmentation fault. */
|
||||
const struct aiocb *l[1] = { &a };
|
||||
TEMP_FAILURE_RETRY (aio_suspend(l, 1, NULL));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -75,5 +75,7 @@ do_test (void)
|
||||
return result;
|
||||
}
|
||||
|
||||
// The test currently hangs and is XFAILed. Reduce the timeout.
|
||||
#define TIMEOUT 1
|
||||
#define TEST_FUNCTION do_test ()
|
||||
#include "../test-skeleton.c"
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/* Test TLS allocation with an interposed malloc.
|
||||
Copyright (C) 2016 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Reuse the test. */
|
||||
#define STACK_SIZE_MB 5
|
||||
#include "tst-tls3.c"
|
||||
|
||||
/* Increase the thread stack size to 10 MiB, so that some thread
|
||||
stacks are actually freed. (The stack cache size is currently
|
||||
hard-wired to 40 MiB in allocatestack.c.) */
|
||||
static long stack_size_in_mb = 10;
|
||||
|
||||
#include <sys/mman.h>
|
||||
|
||||
#define INTERPOSE_THREADS 1
|
||||
#include "../malloc/tst-interpose-aux.c"
|
||||
+9
-1
@@ -29,6 +29,11 @@
|
||||
|
||||
#define THE_SIG SIGUSR1
|
||||
|
||||
/* The stack size can be overriden. With a sufficiently large stack
|
||||
size, thread stacks for terminated threads are freed, but this does
|
||||
not happen with the default size of 1 MiB. */
|
||||
enum { default_stack_size_in_mb = 1 };
|
||||
static long stack_size_in_mb;
|
||||
|
||||
#define N 10
|
||||
static pthread_t th[N];
|
||||
@@ -72,6 +77,9 @@ int nsigs;
|
||||
int
|
||||
do_test (void)
|
||||
{
|
||||
if (stack_size_in_mb == 0)
|
||||
stack_size_in_mb = default_stack_size_in_mb;
|
||||
|
||||
if ((uintptr_t) pthread_self () & (TCB_ALIGNMENT - 1))
|
||||
{
|
||||
puts ("initial thread's struct pthread not aligned enough");
|
||||
@@ -127,7 +135,7 @@ do_test (void)
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (pthread_attr_setstacksize (&a, 1 * 1024 * 1024) != 0)
|
||||
if (pthread_attr_setstacksize (&a, stack_size_in_mb * 1024 * 1024) != 0)
|
||||
{
|
||||
puts ("attr_setstacksize failed");
|
||||
return 1;
|
||||
|
||||
+9
-3
@@ -77,7 +77,7 @@ CONCAT(_nss_db_set,ENTNAME) (int stayopen)
|
||||
keep_db |= stayopen;
|
||||
|
||||
/* Reset the sequential index. */
|
||||
entidx = (const char *) state.header + state.header->valstroffset;
|
||||
entidx = NULL;
|
||||
}
|
||||
|
||||
__libc_lock_unlock (lock);
|
||||
@@ -253,8 +253,14 @@ CONCAT(_nss_db_get,ENTNAME_r) (struct STRUCTURE *result, char *buffer,
|
||||
H_ERRNO_SET (NETDB_INTERNAL);
|
||||
goto out;
|
||||
}
|
||||
entidx = NULL;
|
||||
}
|
||||
|
||||
/* Start from the beginning if freshly initialized or reset
|
||||
requested by set*ent. */
|
||||
if (entidx == NULL)
|
||||
entidx = (const char *) state.header + state.header->valstroffset;
|
||||
|
||||
status = NSS_STATUS_UNAVAIL;
|
||||
if (state.header != MAP_FAILED)
|
||||
{
|
||||
@@ -288,8 +294,8 @@ CONCAT(_nss_db_get,ENTNAME_r) (struct STRUCTURE *result, char *buffer,
|
||||
}
|
||||
if (err < 0)
|
||||
{
|
||||
H_ERRNO_SET (HOST_NOT_FOUND);
|
||||
status = NSS_STATUS_NOTFOUND;
|
||||
H_ERRNO_SET (NETDB_INTERNAL);
|
||||
status = NSS_STATUS_TRYAGAIN;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
+468
-452
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user