diff --git a/ChangeLog b/ChangeLog
-index 2e4afb7..29b7cf5 100644
+index 2e4afb7..4764955 100644
--- a/ChangeLog
+++ b/ChangeLog
-@@ -1,5 +1,182 @@
+@@ -1,5 +1,476 @@
++2016-03-31 Adhemerval Zanella <adhemerval.zanella@linaro.org>
++
++ * elf/tst-dlsym-error.c: Include <string.h> for strchrnul.
++
++2016-03-31 Florian Weimer <fweimer@redhat.com>
++
++ [BZ #19509]
++ * elf/dl-lookup.c (_dl_lookup_symbol_x): Report error even if
++ skip_map != NULL.
++ * elf/tst-dlsym-error.c: New file.
++ * elf/Makefile (tests): Add tst-dlsym-error.
++ (tst-dlsym-error): Link against libdl.
++
++2016-03-07 Florian Weimer <fweimer@redhat.com>
++
++ [BZ #19610]
++ * elf/ldconfig.c (opt_link): Update comment.
++ (options): Update help string for option -X.
++ (search_dir): Unlink stale symbolic link only if updating symbolic
++ links.
++ * elf/tst-ldconfig-X.sh: New file.
++ * elf/Makefile (tests-special): Add tst-ldconfig-X.out.
++ (tst-ldconfig-X.out): New rule to run tst-ldconfig-X.sh.
++
++2016-05-04 Florian Weimer <fweimer@redhat.com>
++
++ [BZ #19779]
++ CVE-2016-1234
++ Avoid copying names of directory entries.
++ * posix/glob.c (DIRENT_MUST_BE, DIRENT_MIGHT_BE_SYMLINK)
++ (DIRENT_MIGHT_BE_DIR, CONVERT_D_INO, CONVERT_D_TYPE)
++ (CONVERT_DIRENT_DIRENT64, REAL_DIR_ENTRY): Remove macros.
++ (struct readdir_result): New type.
++ (D_TYPE_TO_RESULT, D_INO_TO_RESULT, READDIR_RESULT_INITIALIZER)
++ (GL_READDIR): New macros.
++ (readdir_result_might_be_symlink, readdir_result_might_be_dir)
++ (convert_dirent, convert_dirent64): New functions.
++ (glob_in_dir): Use struct readdir_result. Call convert_dirent or
++ convert_dirent64. Adjust references to the readdir result.
++ * sysdeps/unix/sysv/linux/i386/glob64.c:
++ (convert_dirent, GL_READDIR): Redefine for second file inclusion.
++ * posix/bug-glob2.c (LONG_NAME): Define.
++ (filesystem): Add LONG_NAME.
++ (my_DIR): Increase the size of room_for_dirent.
++
++2016-04-29 Florian Weimer <fweimer@redhat.com>
++
++ glob: Simplify and document the interface for the GLOB_ALTDIRFUNC
++ callback function gl_readdir.
++ * posix/glob.c (NAMELEN, CONVERT_D_NAMLEN): Remove.
++ (CONVERT_DIRENT_DIRENT64): Use strcpy instead of memcpy.
++ (glob_in_dir): Remove len. Use strdup instead of malloc and
++ memcpy to copy the name.
++ * manual/pattern.texi (Calling Glob): Document requirements for
++ implementations of the gl_readdir callback function.
++ * manual/examples/mkdirent.c: New example.
++ * posix/bug-glob2.c (my_readdir): Set d_ino to 1 unconditionally,
++ per the manual guidance.
++ * posix/tst-gnuglob.c (my_readdir): Likewise.
++
++2016-04-04 Florian Weimer <fweimer@redhat.com>
++
++ [BZ #19633]
++ Use specified locale for number formatting in strfmon_l.
++ * locale/localeinfo.h (__nl_lookup, _nl_lookup_wstr)
++ (__nl_lookup_word): New inline functions.
++ * include/printf.h (__print_fp_l): Declare.
++ * stdio-common/printf_fp.c (___printf_fp_l): Renamed from
++ ___printf_fp. Add locale argument. Replace _NL_CURRENT with
++ _nl_lookup and _NL_CURRENT_WORD with _nl_lookup_word.
++ (___printf_fp): New function.
++ * stdlib/strfmon_l.c (__printf_fp): Remove declaration.
++ (__vstrfmon_l): Call __printf_fp_l instead of printf_fp.
++ * stdlib/tst-strfmon_l.c (do_test): New test.
++ * stdlib/Makefile (tests): Add kt.
++ (LOCALES): Build additional locales.
++ (tst-strfmon_l.out): Require locales.
++
++2016-03-25 Florian Weimer <fweimer@redhat.com>
++
++ [BZ# 19860]
++ * sysdeps/x86_64/tst-audit10.c (avx512_enabled): Always return
++ zero if the compiler does not provide the AVX512F bit.
++
++2016-03-08 Roland McGrath <roland@hack.frob.com>
++
++ * sysdeps/x86_64/tst-audit10.c: #include <cpu-features.h>.
++ * sysdeps/x86_64/tst-audit10-aux.c: Move audit_test extern decl ...
++ (tst_audit10_aux) [__AVX512F__]: ... here.
++
++2016-03-07 Florian Weimer <fweimer@redhat.com>
++
++ [BZ #19269]
++ * sysdeps/x86_64/Makefile (tst-audit4): Depend on
++ tst-audit4-aux.o.
++ (tst-audit10): Depend on tst-audit10-aux.o.
++ (CFLAGS-tst-audit4-aux.c): Compile with AVX enabled.
++ (CFLAGS-tst-audit10-aux.c): Compile with AVX512 enabled.
++ * sysdeps/x86_64/tst-audit4.c (do_test): Call tst_audit4_aux
++ instead of inline AVX code.
++ * sysdeps/x86_64/tst-audit10.c (do_test): Call tst_audit10_aux
++ instead of inline AVX512 code.
++ * sysdeps/x86_64/tst-audit4-aux.c: New file
++ * sysdeps/x86_64/tst-audit10-aux.c: New file
++
++2016-04-27 Florian Weimer <fweimer@redhat.com>
++
++ [BZ #19825]
++ * resolv/res_send.c (send_vc): Remove early *resplen2
++ initialization. Set *resplen2 on socket error. Call
++ close_and_return_error for other errors.
++
++2016-03-25 Florian Weimer <fweimer@redhat.com>
++
++ [BZ #19868]
++ * resolv/nss_dns/dns-network.c (getanswer_r): Implement additional
++ DNS packet syntax checks (which were not needed before). Skip
++ over non-PTR records.
++
++2016-04-27 Florian Weimer <fweimer@redhat.com>
++
++ [BZ #19831]
++ * resolv/nss_dns/dns-host.c (rrtype_to_rdata_length): New
++ function.
++ (getanswer_r): Check RDATA length against RRTYPE and QTYPE.
++ (gaih_getanswer_slice): Check RDATA length against RRTYPE.
++
++2016-04-27 Florian Weimer <fweimer@redhat.com>
++
++ [BZ #19862]
++ * resolv/nss_dns/dns-host.c (AskedForGot): Remove.
++ (getanswer_r): Do not call syslog.
++ (gaih_getanswer_slice): Likewise.
++ * resolv/gethnamaddr.c (AskedForGot): Remove.
++ (getanswer): Do not call syslog.
++ (gethostbyaddr): Likewise.
++
++2016-04-27 Florian Weimer <fweimer@redhat.com>
++
++ [BZ #19830]
++ * resolv/nss_dns/dns-host.c (getanswer_r): Check RDATA length.
++ (gaih_getanswer_slice): Likewise.
++ * resolv/nss_dns/dns-canon.c (_nss_dns_getcanonname_r): Likewise.
++ Also check for availability of RR metadata.
++
++2016-04-11 Florian Weimer <fweimer@redhat.com>
++
++ [BZ #19865]
++ * resolv/nss_dns/dns-canon.c (_nss_dns_getcanonname_r): Restore
++ original buffer before retry.
++
++2016-04-14 Florian Weimer <fweimer@redhat.com>
++
++ * malloc/arena.c (__malloc_fork_lock_parent)
++ (__malloc_fork_unlock_parent, __malloc_fork_unlock_child): Add
++ internal_function attribute.
++
++2016-04-14 Florian Weimer <fweimer@redhat.com>
++
++ Remove malloc hooks from fork handler. They are no longer needed
++ because malloc runs right before fork, and no malloc calls from
++ other fork handlers are not possible anymore.
++ * malloc/malloc.c (malloc_atfork, free_atfork): Remove
++ declarations.
++ * malloc/arena.c (save_malloc_hook, save_free_hook, save_arena)
++ (ATFORK_ARENA_PTR, malloc_atfork, free_atfork)
++ (atfork_recursive_cntr): Remove.
++ (__malloc_fork_lock_parent): Do not override malloc hooks and
++ thread_arena.
++ (__malloc_fork_unlock_parent): Do not restore malloc hooks and
++ thread_arena.
++ (__malloc_fork_unlock_child): Do not restore malloc hooks. Use
++ thread_arena instead of save_arena.
++
++2016-04-14 Florian Weimer <fweimer@redhat.com>
++
++ [BZ #19431]
++ Run the malloc fork handler as late as possible to avoid deadlocks.
++ * malloc/malloc-internal.h: New file.
++ * malloc/malloc.c: Include it.
++ * malloc/arena.c (ATFORK_MEM): Remove.
++ (__malloc_fork_lock_parent): Rename from ptmalloc_lock_all.
++ Update comment.
++ (__malloc_fork_unlock_parent): Rename from ptmalloc_unlock_all.
++ (__malloc_fork_unlock_child): Rename from ptmalloc_unlock_all2.
++ Remove outdated comment.
++ (ptmalloc_init): Do not call thread_atfork. Remove
++ thread_atfork_static.
++ * malloc/tst-malloc-fork-deadlock.c: New file.
++ * Makefile (tests): Add tst-malloc-fork-deadlock.
++ (tst-malloc-fork-deadlock): Link against libpthread.
++ * manual/memory.texi (Aligned Memory Blocks): Update safety
++ annotation comments.
++ * sysdeps/nptl/fork.c (__libc_fork): Call
++ __malloc_fork_lock_parent, __malloc_fork_unlock_parent,
++ __malloc_fork_unlock_child.
++ * sysdeps/mach/hurd/fork.c (__fork): Likewise.
++
++2016-03-22 Samuel Thibault <samuel.thibault@ens-lyon.org>
++
++ * malloc/Makefile ($(objpfx)tst-malloc-backtrace,
++ $(objpfx)tst-malloc-thread-exit, $(objpfx)tst-malloc-thread-fail): Use
++ $(shared-thread-library) instead of hardcoding the path to libpthread.
++
++2016-02-19 Florian Weimer <fweimer@redhat.com>
++
++ * sysdeps/generic/malloc-machine.h: Assume mutex_init is always
++ available. Do not define NO_THREADS.
++ * malloc/malloc.c: Do not check NO_THREADS.
++ * malloc/arena.c: Likewise.
++
++2016-05-02 Florian Weimer <fweimer@redhat.com>
++
++ [BZ #20031]
++ * hesiod/hesiod.c (get_txt_records): Return error if TXT record is
++ completely empty.
++
++2016-05-02 Florian Weimer <fweimer@redhat.com>
++
++ [BZ #19573]
++ * hesiod/Makefile (libnss_hesiod-routines): Remove hesiod-init.
++ * hesiod/nss_hesiod/hesiod-init.c: Remove file.
++ * hesiod/nss_hesiod/nss_hesiod.h: Likewise.
++ * hesiod/hesiod.h (__hesiod_res_get, __hesiod_res_set): Remove.
++ (hesiod_init, hesiod_end, hesiod_to_bind, hesiod_resolve)
++ (hesiod_free_list): Mark as hidden.
++ * hesiod/hesiod_p (struct hesiod_p): Remove res, free_res,
++ res_set, res_get.
++ * hesiod/hesiod.c: Remove unnecessary forward declarations.
++ (init, __hesiod_res_get, __hesiod_res_set): Remove.
++ (hesiod_init): Remove obsolete res_ninit call.
++ (hesiod_end): Do not free resolver state. Do not invoke callback.
++ (hesiod_bind): Do not call init.
++ (get_txt_records): Use res_mkquery, res_send instead of
++ res_nmkquery, res_nsend.
++ * hesiod/nss_hesiod/hesiod-grp.c (lookup): Call hesiod_init
++ instead of _nss_hesiod_init.
++ (_nss_hesiod_initgroups_dyn): Likewise.
++ * hesiod/nss_hesiod/hesiod-proto.c (lookup): Likewise.
++ * hesiod/nss_hesiod/hesiod-pwd.c (lookup): Likewise.
++ * hesiod/nss_hesiod/hesiod-service.c (lookup): Likewise.
++
++2016-05-02 Florian Weimer <fweimer@redhat.com>
++
++ * hesiod/hesiod.h: Remove RCS keyword.
++ * hesiod/hesiod_p.h: Likewise.
++ * hesiod/hesiod.c: Likewise.
++
++2016-05-04 Florian Weimer <fweimer@redhat.com>
++
++ [BZ #19787]
++ * inet/getnameinfo.c (check_sprintf_result): New function.
++ (CHECKED_SNPRINTF): New macro.
++ (gni_host_inet_numeric): Use CHECKED_SNPRINTF to write the scope
++ to the host buffer.
++ (gni_host_local): Use checked_copy to copy the host name.
++ (gni_serv_inet): Use CHECKED_SNPRINTF to write the service name.
++ (gni_serv_local): Use checked_copy to copy the service name.
++ (getnameinfo): Remove unnecessary truncation of result buffers.
++
++2016-05-04 Florian Weimer <fweimer@redhat.com>
++
++ * inet/getnameinfo.c (gni_host_inet_numeric): Return EAI_OVERFLOW
++ in case of inet_ntop failure.
++
++2016-05-04 Florian Weimer <fweimer@redhat.com>
++
++ * inet/getnameinfo.c (gni_host_inet_name): Use temporaries to
++ avoid long lines.
++ (gni_host_inet_numeric): Likewise. Reduce scope of local
++ variables.
++ (gni_host_inet, gni_host_local): Add comment.
++ (gni_host): Add comment. Use temporary to avoid long lines.
++
++2016-04-29 Florian Weimer <fweimer@redhat.com>
++
++ [BZ #19642]
++ * inet/getnameinfo.c (gni_host_inet_name, gni_host_inet_numeric)
++ (gni_host_inet, gni_host_local, gni_host, gni_serv_inet)
++ (gni_serv_local, gni_serv): New functions extracted from
++ getnameinfo.
++ (getnameinfo): Call gni_host and gni_serv to perform the
++ processing. Always free scratch buffer.
++
++2016-04-28 Florian Weimer <fweimer@redhat.com>
++
++ * inet/getnameinfo.c (getnameinfo): Do not preserve errno.
++
++2016-03-29 Florian Weimer <fweimer@redhat.com>
++
++ [BZ #19837]
++ * nss/nss_db/db-XXX.c (_nss_db_getENTNAME_r): Propagate ERANGE
++ error if parse_line fails.
++
+2016-04-20 Yvan Roux <yvan.roux@linaro.org>
+
+ * stdlib/setenv.c (unsetenv): Fix ambiguous 'else'.
(VERSION): Set to 2.23.
* include/feature.h (__GLIBC_MINOR__): Set to 23.
diff --git a/NEWS b/NEWS
-index c0276cf..a08f96b 100644
+index c0276cf..9c1c638 100644
--- a/NEWS
+++ b/NEWS
-@@ -5,6 +5,29 @@ See the end for copying conditions.
+@@ -5,6 +5,33 @@ See the end for copying conditions.
Please send GNU C library bug reports via <http://sourceware.org/bugzilla/>
using `glibc' in the "product" field.
\f
+ 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 following bugs are resolved with this release:
+
+ [19679] gcc-4.9.3 C++ exception handling broken due to unaligned stack
Version 2.23
* Unicode 8.0.0 Support: Character encoding, character type info, and
-@@ -38,7 +61,7 @@ Version 2.23
+@@ -38,7 +65,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
*** and join the community!" "$LINENO" 5
;;
esac
+diff --git a/elf/Makefile b/elf/Makefile
+index 63a5355..c3dc451 100644
+--- a/elf/Makefile
++++ b/elf/Makefile
+@@ -149,7 +149,7 @@ tests += loadtest restest1 preloadtest loadfail multiload origtest resolvfail \
+ tst-nodelete) \
+ tst-initorder tst-initorder2 tst-relsort1 tst-null-argv \
+ tst-ptrguard1 tst-tlsalign tst-tlsalign-extern tst-nodelete-opened \
+- tst-nodelete2 tst-audit11 tst-audit12
++ tst-nodelete2 tst-audit11 tst-audit12 tst-dlsym-error
+ # reldep9
+ ifeq ($(build-hardcoded-path-in-tests),yes)
+ tests += tst-dlopen-aout
+@@ -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,9 @@ $(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)
++
++$(objpfx)tst-dlsym-error: $(libdl)
+diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c
+index f577759..6d299c1 100644
+--- a/elf/dl-lookup.c
++++ b/elf/dl-lookup.c
+@@ -858,7 +858,6 @@ _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map,
+ if (__glibc_unlikely (current_value.s == NULL))
+ {
+ if ((*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK)
+- && skip_map == NULL
+ && !(GLRO(dl_debug_mask) & DL_DEBUG_UNUSED))
+ {
+ /* We could find no value for a strong reference. */
+diff --git a/elf/ldconfig.c b/elf/ldconfig.c
+index 9c6f2ba..467ca82 100644
+--- a/elf/ldconfig.c
++++ b/elf/ldconfig.c
+@@ -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;
+ }
diff --git a/elf/sln.c b/elf/sln.c
index 9d57be2..f52cb9f 100644
--- a/elf/sln.c
{
if (S_ISDIR (stats.st_mode))
{
+diff --git a/elf/tst-dlsym-error.c b/elf/tst-dlsym-error.c
+new file mode 100644
+index 0000000..fb084c5
+--- /dev/null
++++ b/elf/tst-dlsym-error.c
+@@ -0,0 +1,114 @@
++/* Test error reporting for dlsym, dlvsym failures.
++ Copyright (C) 2016 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, see
++ <http://www.gnu.org/licenses/>. */
++
++#include <dlfcn.h>
++#include <gnu/lib-names.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++
++/* Used to disambiguate symbol names. */
++static int counter;
++
++static void
++test_one (void *handle, const char *name, void *(func) (void *, const char *),
++ const char *suffix)
++{
++ ++counter;
++ char symbol[32];
++ snprintf (symbol, sizeof (symbol), "no_such_symbol_%d", counter);
++ char *expected_message;
++ if (asprintf (&expected_message, ": undefined symbol: %s%s",
++ symbol, suffix) < 0)
++ {
++ printf ("error: asprintf: %m\n");
++ abort ();
++ }
++
++ void *addr = func (handle, symbol);
++ if (addr != NULL)
++ {
++ printf ("error: %s: found symbol \"no_such_symbol\"\n", name);
++ abort ();
++ }
++ const char *message = dlerror ();
++ if (message == NULL)
++ {
++ printf ("error: %s: missing error message\n", name);
++ abort ();
++ }
++ const char *message_without_path = strchrnul (message, ':');
++ if (strcmp (message_without_path, expected_message) != 0)
++ {
++ printf ("error: %s: unexpected error message: %s\n", name, message);
++ abort ();
++ }
++ free (expected_message);
++
++ message = dlerror ();
++ if (message != NULL)
++ {
++ printf ("error: %s: unexpected error message: %s\n", name, message);
++ abort ();
++ }
++}
++
++static void
++test_handles (const char *name, void *(func) (void *, const char *),
++ const char *suffix)
++{
++ test_one (RTLD_DEFAULT, name, func, suffix);
++ test_one (RTLD_NEXT, name, func, suffix);
++
++ void *handle = dlopen (LIBC_SO, RTLD_LAZY);
++ if (handle == NULL)
++ {
++ printf ("error: cannot dlopen %s: %s\n", LIBC_SO, dlerror ());
++ abort ();
++ }
++ test_one (handle, name, func, suffix);
++ dlclose (handle);
++}
++
++static void *
++dlvsym_no_such_version (void *handle, const char *name)
++{
++ return dlvsym (handle, name, "NO_SUCH_VERSION");
++}
++
++static void *
++dlvsym_glibc_private (void *handle, const char *name)
++{
++ return dlvsym (handle, name, "GLIBC_PRIVATE");
++}
++
++static int
++do_test (void)
++{
++ test_handles ("dlsym", dlsym, "");
++ test_handles ("dlvsym", dlvsym_no_such_version,
++ ", version NO_SUCH_VERSION");
++ test_handles ("dlvsym", dlvsym_glibc_private,
++ ", version GLIBC_PRIVATE");
++
++ return 0;
++}
++
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
+diff --git a/elf/tst-ldconfig-X.sh b/elf/tst-ldconfig-X.sh
+new file mode 100644
+index 0000000..0c122a5
+--- /dev/null
++++ b/elf/tst-ldconfig-X.sh
+@@ -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
+diff --git a/hesiod/Makefile b/hesiod/Makefile
+index d68a859..2d1966c 100644
+--- a/hesiod/Makefile
++++ b/hesiod/Makefile
+@@ -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))
+diff --git a/hesiod/hesiod.c b/hesiod/hesiod.c
+index 657dabe..98ddee3 100644
+--- a/hesiod/hesiod.c
++++ b/hesiod/hesiod.c
+@@ -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);
+-}
+diff --git a/hesiod/hesiod.h b/hesiod/hesiod.h
+index 82fce30..c4f5356 100644
+--- a/hesiod/hesiod.h
++++ b/hesiod/hesiod.h
+@@ -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*/
+diff --git a/hesiod/hesiod_p.h b/hesiod/hesiod_p.h
+index 5010d71..1d6d826 100644
+--- a/hesiod/hesiod_p.h
++++ b/hesiod/hesiod_p.h
+@@ -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.
+ *
+@@ -20,10 +37,6 @@
+ */
+
+ /*
+- * $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. */
+ };
+
+diff --git a/hesiod/nss_hesiod/hesiod-grp.c b/hesiod/nss_hesiod/hesiod-grp.c
+index 7e4ecb4..944e5e0 100644
+--- a/hesiod/nss_hesiod/hesiod-grp.c
++++ b/hesiod/nss_hesiod/hesiod-grp.c
+@@ -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");
+diff --git a/hesiod/nss_hesiod/hesiod-init.c b/hesiod/nss_hesiod/hesiod-init.c
+deleted file mode 100644
+index 2315040..0000000
+--- a/hesiod/nss_hesiod/hesiod-init.c
++++ /dev/null
+@@ -1,38 +0,0 @@
+-/* Copyright (C) 2000-2016 Free Software Foundation, Inc.
+- This file is part of the GNU C Library.
+- Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 2000.
+-
+- The GNU C Library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Lesser General Public
+- License as published by the Free Software Foundation; either
+- version 2.1 of the License, or (at your option) any later version.
+-
+- The GNU C Library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Lesser General Public License for more details.
+-
+- You should have received a copy of the GNU Lesser General Public
+- License along with the GNU C Library; if not, see
+- <http://www.gnu.org/licenses/>. */
+-
+-#include <sys/cdefs.h> /* Needs to come before <hesiod.h>. */
+-#include <hesiod.h>
+-#include <resolv.h>
+-#include <stddef.h>
+-
+-#include "nss_hesiod.h"
+-
+-void *
+-_nss_hesiod_init (void)
+-{
+- void *context;
+-
+- if (hesiod_init (&context) == -1)
+- return NULL;
+-
+- /* Use the default (per-thread) resolver state. */
+- __hesiod_res_set (context, &_res, NULL);
+-
+- return context;
+-}
+diff --git a/hesiod/nss_hesiod/hesiod-proto.c b/hesiod/nss_hesiod/hesiod-proto.c
+index 3c59e73..8a13bba 100644
+--- a/hesiod/nss_hesiod/hesiod-proto.c
++++ b/hesiod/nss_hesiod/hesiod-proto.c
+@@ -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);
+diff --git a/hesiod/nss_hesiod/hesiod-pwd.c b/hesiod/nss_hesiod/hesiod-pwd.c
+index 1ddf3e3..c119167 100644
+--- a/hesiod/nss_hesiod/hesiod-pwd.c
++++ b/hesiod/nss_hesiod/hesiod-pwd.c
+@@ -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);
+diff --git a/hesiod/nss_hesiod/hesiod-service.c b/hesiod/nss_hesiod/hesiod-service.c
+index 756345f..2df9cbb 100644
+--- a/hesiod/nss_hesiod/hesiod-service.c
++++ b/hesiod/nss_hesiod/hesiod-service.c
+@@ -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);
+diff --git a/hesiod/nss_hesiod/nss_hesiod.h b/hesiod/nss_hesiod/nss_hesiod.h
+deleted file mode 100644
+index a6ed8ee..0000000
+--- a/hesiod/nss_hesiod/nss_hesiod.h
++++ /dev/null
+@@ -1,20 +0,0 @@
+-/* Copyright (C) 2000-2016 Free Software Foundation, Inc.
+- This file is part of the GNU C Library.
+- Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 2000.
+-
+- 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/>. */
+-
+-/* Initialize a Hesiod context. */
+-extern void *_nss_hesiod_init (void);
+diff --git a/include/printf.h b/include/printf.h
+index c0bd2d2..b12b5dc 100644
+--- a/include/printf.h
++++ b/include/printf.h
+@@ -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
diff --git a/include/sys/auxv.h b/include/sys/auxv.h
new file mode 100644
index 0000000..dede2c3
+++ b/include/sys/auxv.h
@@ -0,0 +1 @@
+#include <misc/sys/auxv.h>
+diff --git a/inet/getnameinfo.c b/inet/getnameinfo.c
+index 40f67f0..283da55 100644
+--- a/inet/getnameinfo.c
++++ b/inet/getnameinfo.c
+@@ -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;
++}
+
+-int
+-getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host,
+- socklen_t hostlen, char *serv, socklen_t servlen,
+- int flags)
++/* 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 serrno = errno;
+ int herrno;
+ struct hostent th;
+- int ok = 0;
+- struct scratch_buffer tmpbuf;
++ 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;
++ }
+
+- scratch_buffer_init (&tmpbuf);
++ 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)
++{
+ 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;
+ }
+
+- 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;
++ struct scratch_buffer tmpbuf;
++ scratch_buffer_init (&tmpbuf);
+
+- default:
+- return EAI_FAMILY;
++ if (host != NULL && hostlen > 0)
++ {
++ 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)
+diff --git a/locale/localeinfo.h b/locale/localeinfo.h
+index 5c4e6ef..94627f3 100644
+--- a/locale/localeinfo.h
++++ b/locale/localeinfo.h
+@@ -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;
+diff --git a/localedata/ChangeLog b/localedata/ChangeLog
+index 05ccd90..dd1c2b1 100644
+--- a/localedata/ChangeLog
++++ b/localedata/ChangeLog
+@@ -1,3 +1,10 @@
++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.
+diff --git a/localedata/locales/sr_ME b/localedata/locales/sr_ME
+index 4f243dc..dd68df8 100644
+--- a/localedata/locales/sr_ME
++++ b/localedata/locales/sr_ME
+@@ -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
+diff --git a/localedata/locales/sr_RS b/localedata/locales/sr_RS
+index 2ae085b..ffea86f 100644
+--- a/localedata/locales/sr_RS
++++ b/localedata/locales/sr_RS
+@@ -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
+diff --git a/localedata/locales/sr_RS@latin b/localedata/locales/sr_RS@latin
+index da6628b..fd10ea6 100644
+--- a/localedata/locales/sr_RS@latin
++++ b/localedata/locales/sr_RS@latin
+@@ -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
+diff --git a/malloc/Makefile b/malloc/Makefile
+index 360288b..3283f4f 100644
+--- a/malloc/Makefile
++++ b/malloc/Makefile
+@@ -29,7 +29,7 @@ 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
+ test-srcs = tst-mtrace
+
+ routines = malloc morecore mcheck mtrace obstack \
+@@ -46,12 +46,10 @@ extra-libs-others = $(extra-libs)
+ 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
+diff --git a/malloc/arena.c b/malloc/arena.c
+index 1edb4d4..47715b6 100644
+--- a/malloc/arena.c
++++ b/malloc/arena.c
+@@ -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;
+-
+-# 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 *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 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. */
+
+-/* 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)
++void
++internal_function
++__malloc_fork_lock_parent (void)
+ {
+- mstate ar_ptr;
+-
+ if (__malloc_initialized < 1)
+ return;
+
+ /* We do not acquire free_list_lock here because we completely
+- reconstruct free_list in 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);
+
+diff --git a/malloc/malloc-internal.h b/malloc/malloc-internal.h
+new file mode 100644
+index 0000000..b830d3f
+--- /dev/null
++++ b/malloc/malloc-internal.h
+@@ -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 */
+diff --git a/malloc/malloc.c b/malloc/malloc.c
+index d20d595..39e4298 100644
+--- a/malloc/malloc.c
++++ b/malloc/malloc.c
+@@ -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 ------------------ */
+
+diff --git a/malloc/tst-malloc-fork-deadlock.c b/malloc/tst-malloc-fork-deadlock.c
+new file mode 100644
+index 0000000..94549ca
+--- /dev/null
++++ b/malloc/tst-malloc-fork-deadlock.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;
++}
+diff --git a/manual/examples/mkdirent.c b/manual/examples/mkdirent.c
+new file mode 100644
+index 0000000..f8400f4
+--- /dev/null
++++ b/manual/examples/mkdirent.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;
++}
+diff --git a/manual/memory.texi b/manual/memory.texi
+index 700555e..cdeb472 100644
+--- a/manual/memory.texi
++++ b/manual/memory.texi
+@@ -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
+diff --git a/manual/pattern.texi b/manual/pattern.texi
+index d1b9275..565e7eb 100644
+--- a/manual/pattern.texi
++++ b/manual/pattern.texi
+@@ -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}
diff --git a/math/Makefile b/math/Makefile
index 7d573a0..6aa87f9 100644
--- a/math/Makefile
old = *loc;
*loc = new;
+diff --git a/nss/nss_db/db-XXX.c b/nss/nss_db/db-XXX.c
+index 03c18d7..125a5e9 100644
+--- a/nss/nss_db/db-XXX.c
++++ b/nss/nss_db/db-XXX.c
+@@ -288,8 +288,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;
+ }
+
diff --git a/po/be.po b/po/be.po
index 66d1235..ffb39b4 100644
--- a/po/be.po
#~ msgid "compile-time support for database policy missing"
#~ msgstr "compile-time 支援用於資料庫策略缺少"
+diff --git a/posix/bug-glob2.c b/posix/bug-glob2.c
+index ddf5ec9..5873e08 100644
+--- a/posix/bug-glob2.c
++++ b/posix/bug-glob2.c
+@@ -40,6 +40,17 @@
+ # define PRINTF(fmt, args...)
+ #endif
+
++#define LONG_NAME \
++ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
++ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
++ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
++ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
++ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
++ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
++ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
++ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
++ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
++ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+
+ static struct
+ {
+@@ -58,6 +69,7 @@ static struct
+ { ".", 3, DT_DIR, 0755 },
+ { "..", 3, DT_DIR, 0755 },
+ { "a", 3, DT_REG, 0644 },
++ { LONG_NAME, 3, DT_REG, 0644 },
+ { "unreadable", 2, DT_DIR, 0111 },
+ { ".", 3, DT_DIR, 0111 },
+ { "..", 3, DT_DIR, 0755 },
+@@ -75,7 +87,7 @@ typedef struct
+ int level;
+ int idx;
+ struct dirent d;
+- char room_for_dirent[NAME_MAX];
++ char room_for_dirent[sizeof (LONG_NAME)];
+ } my_DIR;
+
+
+@@ -193,7 +205,7 @@ my_readdir (void *gdir)
+ return NULL;
+ }
+
+- dir->d.d_ino = dir->idx;
++ dir->d.d_ino = 1; /* glob should not skip this entry. */
+
+ #ifdef _DIRENT_HAVE_D_TYPE
+ dir->d.d_type = filesystem[dir->idx].type;
+diff --git a/posix/glob.c b/posix/glob.c
+index 0c04c3c..ea4b0b6 100644
+--- a/posix/glob.c
++++ b/posix/glob.c
+@@ -24,7 +24,9 @@
+ #include <errno.h>
+ #include <sys/types.h>
+ #include <sys/stat.h>
++#include <stdbool.h>
+ #include <stddef.h>
++#include <stdint.h>
+
+ /* Outcomment the following line for production quality code. */
+ /* #define NDEBUG 1 */
+@@ -57,10 +59,8 @@
+
+ #if defined HAVE_DIRENT_H || defined __GNU_LIBRARY__
+ # include <dirent.h>
+-# define NAMLEN(dirent) strlen((dirent)->d_name)
+ #else
+ # define dirent direct
+-# define NAMLEN(dirent) (dirent)->d_namlen
+ # ifdef HAVE_SYS_NDIR_H
+ # include <sys/ndir.h>
+ # endif
+@@ -75,82 +75,8 @@
+ # endif /* HAVE_VMSDIR_H */
+ #endif
+
+-
+-/* In GNU systems, <dirent.h> defines this macro for us. */
+-#ifdef _D_NAMLEN
+-# undef NAMLEN
+-# define NAMLEN(d) _D_NAMLEN(d)
+-#endif
+-
+-/* When used in the GNU libc the symbol _DIRENT_HAVE_D_TYPE is available
+- if the `d_type' member for `struct dirent' is available.
+- HAVE_STRUCT_DIRENT_D_TYPE plays the same role in GNULIB. */
+-#if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE
+-/* True if the directory entry D must be of type T. */
+-# define DIRENT_MUST_BE(d, t) ((d)->d_type == (t))
+-
+-/* True if the directory entry D might be a symbolic link. */
+-# define DIRENT_MIGHT_BE_SYMLINK(d) \
+- ((d)->d_type == DT_UNKNOWN || (d)->d_type == DT_LNK)
+-
+-/* True if the directory entry D might be a directory. */
+-# define DIRENT_MIGHT_BE_DIR(d) \
+- ((d)->d_type == DT_DIR || DIRENT_MIGHT_BE_SYMLINK (d))
+-
+-#else /* !HAVE_D_TYPE */
+-# define DIRENT_MUST_BE(d, t) false
+-# define DIRENT_MIGHT_BE_SYMLINK(d) true
+-# define DIRENT_MIGHT_BE_DIR(d) true
+-#endif /* HAVE_D_TYPE */
+-
+-/* If the system has the `struct dirent64' type we use it internally. */
+-#if defined _LIBC && !defined COMPILE_GLOB64
+-# if defined HAVE_DIRENT_H || defined __GNU_LIBRARY__
+-# define CONVERT_D_NAMLEN(d64, d32)
+-# else
+-# define CONVERT_D_NAMLEN(d64, d32) \
+- (d64)->d_namlen = (d32)->d_namlen;
+-# endif
+-
+-# if (defined POSIX || defined WINDOWS32) && !defined __GNU_LIBRARY__
+-# define CONVERT_D_INO(d64, d32)
+-# else
+-# define CONVERT_D_INO(d64, d32) \
+- (d64)->d_ino = (d32)->d_ino;
+-# endif
+-
+-# ifdef _DIRENT_HAVE_D_TYPE
+-# define CONVERT_D_TYPE(d64, d32) \
+- (d64)->d_type = (d32)->d_type;
+-# else
+-# define CONVERT_D_TYPE(d64, d32)
+-# endif
+-
+-# define CONVERT_DIRENT_DIRENT64(d64, d32) \
+- memcpy ((d64)->d_name, (d32)->d_name, NAMLEN (d32) + 1); \
+- CONVERT_D_NAMLEN (d64, d32) \
+- CONVERT_D_INO (d64, d32) \
+- CONVERT_D_TYPE (d64, d32)
+-#endif
+-
+-
+-#if (defined POSIX || defined WINDOWS32) && !defined __GNU_LIBRARY__
+-/* Posix does not require that the d_ino field be present, and some
+- systems do not provide it. */
+-# define REAL_DIR_ENTRY(dp) 1
+-#else
+-# define REAL_DIR_ENTRY(dp) (dp->d_ino != 0)
+-#endif /* POSIX */
+-
+ #include <stdlib.h>
+ #include <string.h>
+-
+-/* NAME_MAX is usually defined in <dirent.h> or <limits.h>. */
+-#include <limits.h>
+-#ifndef NAME_MAX
+-# define NAME_MAX (sizeof (((struct dirent *) 0)->d_name))
+-#endif
+-
+ #include <alloca.h>
+
+ #ifdef _LIBC
+@@ -195,8 +121,111 @@
+ \f
+ static const char *next_brace_sub (const char *begin, int flags) __THROWNL;
+
++/* A representation of a directory entry which does not depend on the
++ layout of struct dirent, or the size of ino_t. */
++struct readdir_result
++{
++ const char *name;
++# if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE
++ uint8_t type;
++# endif
++ bool skip_entry;
++};
++
++# if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE
++/* Initializer based on the d_type member of struct dirent. */
++# define D_TYPE_TO_RESULT(source) (source)->d_type,
++
++/* True if the directory entry D might be a symbolic link. */
++static bool
++readdir_result_might_be_symlink (struct readdir_result d)
++{
++ return d.type == DT_UNKNOWN || d.type == DT_LNK;
++}
++
++/* True if the directory entry D might be a directory. */
++static bool
++readdir_result_might_be_dir (struct readdir_result d)
++{
++ return d.type == DT_DIR || readdir_result_might_be_symlink (d);
++}
++# else /* defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE */
++# define D_TYPE_TO_RESULT(source)
++
++/* If we do not have type information, symbolic links and directories
++ are always a possibility. */
++
++static bool
++readdir_result_might_be_symlink (struct readdir_result d)
++{
++ return true;
++}
++
++static bool
++readdir_result_might_be_dir (struct readdir_result d)
++{
++ return true;
++}
++
++# endif /* defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE */
++
++# if (defined POSIX || defined WINDOWS32) && !defined __GNU_LIBRARY__
++/* Initializer for skip_entry. POSIX does not require that the d_ino
++ field be present, and some systems do not provide it. */
++# define D_INO_TO_RESULT(source) false,
++# else
++# define D_INO_TO_RESULT(source) (source)->d_ino == 0,
++# endif
++
++/* Construct an initializer for a struct readdir_result object from a
++ struct dirent *. No copy of the name is made. */
++#define READDIR_RESULT_INITIALIZER(source) \
++ { \
++ source->d_name, \
++ D_TYPE_TO_RESULT (source) \
++ D_INO_TO_RESULT (source) \
++ }
++
+ #endif /* !defined _LIBC || !defined GLOB_ONLY_P */
+
++/* Call gl_readdir on STREAM. This macro can be overridden to reduce
++ type safety if an old interface version needs to be supported. */
++#ifndef GL_READDIR
++# define GL_READDIR(pglob, stream) ((pglob)->gl_readdir (stream))
++#endif
++
++/* Extract name and type from directory entry. No copy of the name is
++ made. If SOURCE is NULL, result name is NULL. Keep in sync with
++ convert_dirent64 below. */
++static struct readdir_result
++convert_dirent (const struct dirent *source)
++{
++ if (source == NULL)
++ {
++ struct readdir_result result = { NULL, };
++ return result;
++ }
++ struct readdir_result result = READDIR_RESULT_INITIALIZER (source);
++ return result;
++}
++
++#ifndef COMPILE_GLOB64
++/* Like convert_dirent, but works on struct dirent64 instead. Keep in
++ sync with convert_dirent above. */
++static struct readdir_result
++convert_dirent64 (const struct dirent64 *source)
++{
++ if (source == NULL)
++ {
++ struct readdir_result result = { NULL, };
++ return result;
++ }
++ struct readdir_result result = READDIR_RESULT_INITIALIZER (source);
++ return result;
++}
++#endif
++
++
+ #ifndef attribute_hidden
+ # define attribute_hidden
+ #endif
+@@ -1553,56 +1582,36 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
+
+ while (1)
+ {
+- const char *name;
+- size_t len;
+-#if defined _LIBC && !defined COMPILE_GLOB64
+- struct dirent64 *d;
+- union
+- {
+- struct dirent64 d64;
+- char room [offsetof (struct dirent64, d_name[0])
+- + NAME_MAX + 1];
+- }
+- d64buf;
+-
+- if (__glibc_unlikely (flags & GLOB_ALTDIRFUNC))
+- {
+- struct dirent *d32 = (*pglob->gl_readdir) (stream);
+- if (d32 != NULL)
+- {
+- CONVERT_DIRENT_DIRENT64 (&d64buf.d64, d32);
+- d = &d64buf.d64;
+- }
+- else
+- d = NULL;
+- }
+- else
+- d = __readdir64 (stream);
++ struct readdir_result d;
++ {
++ if (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0))
++ d = convert_dirent (GL_READDIR (pglob, stream));
++ else
++ {
++#ifdef COMPILE_GLOB64
++ d = convert_dirent (__readdir (stream));
+ #else
+- struct dirent *d = (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
+- ? ((struct dirent *)
+- (*pglob->gl_readdir) (stream))
+- : __readdir (stream));
++ d = convert_dirent64 (__readdir64 (stream));
+ #endif
+- if (d == NULL)
++ }
++ }
++ if (d.name == NULL)
+ break;
+- if (! REAL_DIR_ENTRY (d))
++ if (d.skip_entry)
+ continue;
+
+ /* If we shall match only directories use the information
+ provided by the dirent call if possible. */
+- if ((flags & GLOB_ONLYDIR) && !DIRENT_MIGHT_BE_DIR (d))
++ if ((flags & GLOB_ONLYDIR) && !readdir_result_might_be_dir (d))
+ continue;
+
+- name = d->d_name;
+-
+- if (fnmatch (pattern, name, fnm_flags) == 0)
++ if (fnmatch (pattern, d.name, fnm_flags) == 0)
+ {
+ /* If the file we found is a symlink we have to
+ make sure the target file exists. */
+- if (!DIRENT_MIGHT_BE_SYMLINK (d)
+- || link_exists_p (dfd, directory, dirlen, name, pglob,
+- flags))
++ if (!readdir_result_might_be_symlink (d)
++ || link_exists_p (dfd, directory, dirlen, d.name,
++ pglob, flags))
+ {
+ if (cur == names->count)
+ {
+@@ -1622,12 +1631,10 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
+ names = newnames;
+ cur = 0;
+ }
+- len = NAMLEN (d);
+- names->name[cur] = (char *) malloc (len + 1);
++ names->name[cur] = strdup (d.name);
+ if (names->name[cur] == NULL)
+ goto memory_error;
+- *((char *) mempcpy (names->name[cur++], name, len))
+- = '\0';
++ ++cur;
+ ++nfound;
+ }
+ }
+diff --git a/posix/tst-gnuglob.c b/posix/tst-gnuglob.c
+index 992b997..b7b859b 100644
+--- a/posix/tst-gnuglob.c
++++ b/posix/tst-gnuglob.c
+@@ -211,7 +211,7 @@ my_readdir (void *gdir)
+ return NULL;
+ }
+
+- dir->d.d_ino = dir->idx;
++ dir->d.d_ino = 1; /* glob should not skip this entry. */
+
+ #ifdef _DIRENT_HAVE_D_TYPE
+ dir->d.d_type = filesystem[dir->idx].type;
+diff --git a/resolv/gethnamaddr.c b/resolv/gethnamaddr.c
+index 3a8e9b1..4720fc8 100644
+--- a/resolv/gethnamaddr.c
++++ b/resolv/gethnamaddr.c
+@@ -70,7 +70,6 @@ static char sccsid[] = "@(#)gethostnamadr.c 8.1 (Berkeley) 6/4/93";
+ #include <resolv.h>
+ #include <ctype.h>
+ #include <errno.h>
+-#include <syslog.h>
+
+ #define RESOLVSORT
+
+@@ -100,9 +99,6 @@ static char sccsid[] = "@(#)gethostnamadr.c 8.1 (Berkeley) 6/4/93";
+ #define MAXALIASES 35
+ #define MAXADDRS 35
+
+-static const char AskedForGot[] =
+- "gethostby*.getanswer: asked for \"%s\", got \"%s\"";
+-
+ static char *h_addr_ptrs[MAXADDRS + 1];
+
+ static struct hostent host;
+@@ -335,20 +331,12 @@ getanswer (const querybuf *answer, int anslen, const char *qname, int qtype)
+ * uses many different types in responses that do not
+ * match QTYPE.
+ */
+- if ((_res.options & RES_USE_DNSSEC) == 0) {
+- syslog(LOG_NOTICE|LOG_AUTH,
+- "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
+- qname, p_class(C_IN), p_type(qtype),
+- p_type(type));
+- }
+ cp += n;
+ continue; /* XXX - had_error++ ? */
+ }
+ switch (type) {
+ case T_PTR:
+ if (strcasecmp(tname, bp) != 0) {
+- syslog(LOG_NOTICE|LOG_AUTH,
+- AskedForGot, qname, bp);
+ cp += n;
+ continue; /* XXX - had_error++ ? */
+ }
+@@ -397,8 +385,6 @@ getanswer (const querybuf *answer, int anslen, const char *qname, int qtype)
+ case T_A:
+ case T_AAAA:
+ if (strcasecmp(host.h_name, bp) != 0) {
+- syslog(LOG_NOTICE|LOG_AUTH,
+- AskedForGot, host.h_name, bp);
+ cp += n;
+ continue; /* XXX - had_error++ ? */
+ }
+@@ -740,9 +726,6 @@ gethostbyaddr (const void *addr, socklen_t len, int af)
+ _res.options &= ~RES_DNSRCH;
+ _res.options |= RES_DEFNAMES;
+ if (!(rhp = gethostbyname(hname2))) {
+- syslog(LOG_NOTICE|LOG_AUTH,
+- "gethostbyaddr: No A record for %s (verifying [%s])",
+- hname2, inet_ntoa(*((struct in_addr *)addr)));
+ _res.options = old_options;
+ __set_h_errno (HOST_NOT_FOUND);
+ return (NULL);
+@@ -752,9 +735,6 @@ gethostbyaddr (const void *addr, socklen_t len, int af)
+ if (!memcmp(*haddr, addr, INADDRSZ))
+ break;
+ if (!*haddr) {
+- syslog(LOG_NOTICE|LOG_AUTH,
+- "gethostbyaddr: A record of %s != PTR record [%s]",
+- hname2, inet_ntoa(*((struct in_addr *)addr)));
+ __set_h_errno (HOST_NOT_FOUND);
+ return (NULL);
+ }
+diff --git a/resolv/nss_dns/dns-canon.c b/resolv/nss_dns/dns-canon.c
+index 27255fd..072104f 100644
+--- a/resolv/nss_dns/dns-canon.c
++++ b/resolv/nss_dns/dns-canon.c
+@@ -103,6 +103,11 @@ _nss_dns_getcanonname_r (const char *name, char *buffer, size_t buflen,
+
+ ptr += s;
+
++ /* Check that there are enough bytes for the RR
++ metadata. */
++ if (endptr - ptr < 10)
++ goto unavail;
++
+ /* Check whether type and class match. */
+ uint_fast16_t type;
+ NS_GET16 (type, ptr);
+@@ -137,13 +142,25 @@ _nss_dns_getcanonname_r (const char *name, char *buffer, size_t buflen,
+ if (__ns_get16 (ptr) != ns_c_in)
+ goto unavail;
+
+- /* Also skip over the TTL. */
++ /* Also skip over class and TTL. */
+ ptr += sizeof (uint16_t) + sizeof (uint32_t);
+
+- /* Skip over the data length and data. */
+- ptr += sizeof (uint16_t) + __ns_get16 (ptr);
++ /* Skip over RDATA length and RDATA itself. */
++ uint16_t rdatalen = __ns_get16 (ptr);
++ ptr += sizeof (uint16_t);
++ /* Not enough room for RDATA. */
++ if (endptr - ptr < rdatalen)
++ goto unavail;
++ ptr += rdatalen;
+ }
+ }
++
++ /* Restore original buffer before retry. */
++ if (ansp.ptr != buf)
++ {
++ free (ansp.ptr);
++ ansp.ptr = buf;
++ }
+ }
+
+ out:
+diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c
+index 8599f4c..403a005 100644
+--- a/resolv/nss_dns/dns-host.c
++++ b/resolv/nss_dns/dns-host.c
+@@ -78,7 +78,6 @@
+ #include <stdlib.h>
+ #include <stddef.h>
+ #include <string.h>
+-#include <sys/syslog.h>
+
+ #include "nsswitch.h"
+
+@@ -99,10 +98,6 @@
+ #endif
+ #define MAXHOSTNAMELEN 256
+
+-static const char AskedForGot[] = "\
+-gethostby*.getanswer: asked for \"%s\", got \"%s\"";
+-
+-
+ /* We need this time later. */
+ typedef union querybuf
+ {
+@@ -139,6 +134,22 @@ extern enum nss_status _nss_dns_gethostbyname3_r (const char *name, int af,
+ char **canonp);
+ hidden_proto (_nss_dns_gethostbyname3_r)
+
++/* Return the expected RDATA length for an address record type (A or
++ AAAA). */
++static int
++rrtype_to_rdata_length (int type)
++{
++ switch (type)
++ {
++ case T_A:
++ return INADDRSZ;
++ case T_AAAA:
++ return IN6ADDRSZ;
++ default:
++ return -1;
++ }
++}
++
+ enum nss_status
+ _nss_dns_gethostbyname3_r (const char *name, int af, struct hostent *result,
+ char *buffer, size_t buflen, int *errnop,
+@@ -751,6 +762,14 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
+ cp += INT32SZ; /* TTL */
+ n = __ns_get16 (cp);
+ cp += INT16SZ; /* len */
++
++ if (end_of_message - cp < n)
++ {
++ /* RDATA extends beyond the end of the packet. */
++ ++had_error;
++ continue;
++ }
++
+ if (__glibc_unlikely (class != C_IN))
+ {
+ /* XXX - debug? syslog? */
+@@ -830,14 +849,6 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
+ have_to_map = 1;
+ else if (__glibc_unlikely (type != qtype))
+ {
+- /* Log a low priority message if we get an unexpected record, but
+- skip it if we are using DNSSEC since it uses many different types
+- in responses that do not match QTYPE. */
+- if ((_res.options & RES_USE_DNSSEC) == 0)
+- syslog (LOG_NOTICE | LOG_AUTH,
+- "gethostby*.getanswer: asked for \"%s %s %s\", "
+- "got type \"%s\"",
+- qname, p_class (C_IN), p_type (qtype), p_type (type));
+ cp += n;
+ continue; /* XXX - had_error++ ? */
+ }
+@@ -847,7 +858,6 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
+ case T_PTR:
+ if (__glibc_unlikely (strcasecmp (tname, bp) != 0))
+ {
+- syslog (LOG_NOTICE | LOG_AUTH, AskedForGot, qname, bp);
+ cp += n;
+ continue; /* XXX - had_error++ ? */
+ }
+@@ -891,10 +901,18 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
+ case T_AAAA:
+ if (__builtin_expect (strcasecmp (result->h_name, bp), 0) != 0)
+ {
+- syslog (LOG_NOTICE | LOG_AUTH, AskedForGot, result->h_name, bp);
+ cp += n;
+ continue; /* XXX - had_error++ ? */
+ }
++
++ /* Stop parsing at a record whose length is incorrect. */
++ if (n != rrtype_to_rdata_length (type))
++ {
++ ++had_error;
++ break;
++ }
++
++ /* Skip records of the wrong type. */
+ if (n != result->h_length)
+ {
+ cp += n;
+@@ -1077,6 +1095,13 @@ gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname,
+ n = __ns_get16 (cp);
+ cp += INT16SZ; /* len */
+
++ if (end_of_message - cp < n)
++ {
++ /* RDATA extends beyond the end of the packet. */
++ ++had_error;
++ continue;
++ }
++
+ if (class != C_IN)
+ {
+ cp += n;
+@@ -1124,32 +1149,25 @@ gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname,
+ }
+ continue;
+ }
+-#if 1
+- // We should not see any types other than those explicitly listed
+- // below. Some types sent by server seem missing, though. Just
+- // collect the data for now.
+- if (__glibc_unlikely (type != T_A && type != T_AAAA))
+-#else
+- if (__builtin_expect (type == T_SIG, 0)
+- || __builtin_expect (type == T_KEY, 0)
+- || __builtin_expect (type == T_NXT, 0)
+- || __builtin_expect (type == T_PTR, 0)
+- || __builtin_expect (type == T_DNAME, 0))
+-#endif
+- {
+- /* We don't support DNSSEC yet. For now, ignore the record
+- and send a low priority message to syslog.
+
+- We also don't expect T_PTR or T_DNAME messages. */
+- syslog (LOG_DEBUG | LOG_AUTH,
+- "getaddrinfo*.gaih_getanswer: got type \"%s\"",
+- p_type (type));
++ /* Stop parsing if we encounter a record with incorrect RDATA
++ length. */
++ if (type == T_A || type == T_AAAA)
++ {
++ if (n != rrtype_to_rdata_length (type))
++ {
++ ++had_error;
++ continue;
++ }
++ }
++ else
++ {
++ /* Skip unknown records. */
+ cp += n;
+ continue;
+ }
+- if (type != T_A && type != T_AAAA)
+- abort ();
+
++ assert (type == T_A || type == T_AAAA);
+ if (*pat == NULL)
+ {
+ uintptr_t pad = (-(uintptr_t) buffer
+@@ -1183,12 +1201,6 @@ gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname,
+ }
+
+ (*pat)->family = type == T_A ? AF_INET : AF_INET6;
+- if (__builtin_expect ((type == T_A && n != INADDRSZ)
+- || (type == T_AAAA && n != IN6ADDRSZ), 0))
+- {
+- ++had_error;
+- continue;
+- }
+ memcpy ((*pat)->addr, cp, n);
+ cp += n;
+ (*pat)->scopeid = 0;
diff --git a/resolv/nss_dns/dns-network.c b/resolv/nss_dns/dns-network.c
-index 2eb2f67..8f301a7 100644
+index 2eb2f67..ad6acff 100644
--- a/resolv/nss_dns/dns-network.c
+++ b/resolv/nss_dns/dns-network.c
@@ -118,17 +118,14 @@ _nss_dns_getnetbyname_r (const char *name, struct netent *result,
1024, &net_buffer.ptr, NULL, NULL, NULL, NULL);
if (anslen < 0)
{
+@@ -348,10 +345,23 @@ getanswer_r (const querybuf *answer, int anslen, struct netent *result,
+ if (n < 0 || res_dnok (bp) == 0)
+ break;
+ cp += n;
++
++ if (end_of_message - cp < 10)
++ {
++ __set_h_errno (NO_RECOVERY);
++ return NSS_STATUS_UNAVAIL;
++ }
++
+ GETSHORT (type, cp);
+ GETSHORT (class, cp);
+ cp += INT32SZ; /* TTL */
+- GETSHORT (n, cp);
++ uint16_t rdatalen;
++ GETSHORT (rdatalen, cp);
++ if (end_of_message - cp < rdatalen)
++ {
++ __set_h_errno (NO_RECOVERY);
++ return NSS_STATUS_UNAVAIL;
++ }
+
+ if (class == C_IN && type == T_PTR)
+ {
+@@ -373,7 +383,7 @@ getanswer_r (const querybuf *answer, int anslen, struct netent *result,
+ cp += n;
+ return NSS_STATUS_UNAVAIL;
+ }
+- cp += n;
++ cp += rdatalen;
+ if (alias_pointer + 2 < &net_data->aliases[MAX_NR_ALIASES])
+ {
+ *alias_pointer++ = bp;
+@@ -384,6 +394,9 @@ getanswer_r (const querybuf *answer, int anslen, struct netent *result,
+ ++have_answer;
+ }
+ }
++ else
++ /* Skip over unknown record data. */
++ cp += rdatalen;
+ }
+
+ if (have_answer)
diff --git a/resolv/res_init.c b/resolv/res_init.c
index e0b6a80..6c951f5 100644
--- a/resolv/res_init.c
if (statp->_u._ext.nssocks[ns] != -1) {
close_not_cancel_no_status(statp->_u._ext.nssocks[ns]);
diff --git a/resolv/res_send.c b/resolv/res_send.c
-index 25c19f1..b4efcb6 100644
+index 25c19f1..2c0bae1 100644
--- a/resolv/res_send.c
+++ b/resolv/res_send.c
@@ -649,6 +649,18 @@ get_nsaddr (res_state statp, int n)
/* The send_vc function is responsible for sending a DNS query over TCP
to the nameserver numbered NS from the res_state STATP i.e.
EXT(statp).nssocks[ns]. The function supports sending both IPv4 and
-@@ -1114,7 +1126,11 @@ send_dg(res_state statp,
+@@ -750,8 +762,6 @@ send_vc(res_state statp,
+ u_short len2;
+ u_char *cp;
+
+- if (resplen2 != NULL)
+- *resplen2 = 0;
+ connreset = 0;
+ same_ns:
+ truncating = 0;
+@@ -777,6 +787,8 @@ send_vc(res_state statp,
+ if (statp->_vcsock < 0) {
+ *terrno = errno;
+ Perror(statp, stderr, "socket(vc)", errno);
++ if (resplen2 != NULL)
++ *resplen2 = 0;
+ return (-1);
+ }
+ __set_errno (0);
+@@ -786,8 +798,7 @@ send_vc(res_state statp,
+ : sizeof (struct sockaddr_in6)) < 0) {
+ *terrno = errno;
+ Aerror(statp, stderr, "connect/vc", errno, nsap);
+- __res_iclose(statp, false);
+- return (0);
++ return close_and_return_error (statp, resplen2);
+ }
+ statp->_flags |= RES_F_VC;
+ }
+@@ -810,8 +821,7 @@ send_vc(res_state statp,
+ if (TEMP_FAILURE_RETRY (writev(statp->_vcsock, iov, niov)) != explen) {
+ *terrno = errno;
+ Perror(statp, stderr, "write failed", errno);
+- __res_iclose(statp, false);
+- return (0);
++ return close_and_return_error (statp, resplen2);
+ }
+ /*
+ * Receive length & response
+@@ -833,7 +843,6 @@ send_vc(res_state statp,
+ if (n <= 0) {
+ *terrno = errno;
+ Perror(statp, stderr, "read failed", errno);
+- __res_iclose(statp, false);
+ /*
+ * A long running process might get its TCP
+ * connection reset if the remote server was
+@@ -843,11 +852,13 @@ send_vc(res_state statp,
+ * instead of failing. We only allow one reset
+ * per query to prevent looping.
+ */
+- if (*terrno == ECONNRESET && !connreset) {
+- connreset = 1;
+- goto same_ns;
+- }
+- return (0);
++ if (*terrno == ECONNRESET && !connreset)
++ {
++ __res_iclose (statp, false);
++ connreset = 1;
++ goto same_ns;
++ }
++ return close_and_return_error (statp, resplen2);
+ }
+ int rlen = ntohs (rlen16);
+
+@@ -879,11 +890,11 @@ send_vc(res_state statp,
+ /* Always allocate MAXPACKET, callers expect
+ this specific size. */
+ u_char *newp = malloc (MAXPACKET);
+- if (newp == NULL) {
+- *terrno = ENOMEM;
+- __res_iclose(statp, false);
+- return (0);
+- }
++ if (newp == NULL)
++ {
++ *terrno = ENOMEM;
++ return close_and_return_error (statp, resplen2);
++ }
+ *thisanssizp = MAXPACKET;
+ *thisansp = newp;
+ if (thisansp == ansp2)
+@@ -910,8 +921,7 @@ send_vc(res_state statp,
+ Dprint(statp->options & RES_DEBUG,
+ (stdout, ";; undersized: %d\n", len));
+ *terrno = EMSGSIZE;
+- __res_iclose(statp, false);
+- return (0);
++ return close_and_return_error (statp, resplen2);
+ }
+
+ cp = *thisansp;
+@@ -922,8 +932,7 @@ send_vc(res_state statp,
+ if (__glibc_unlikely (n <= 0)) {
+ *terrno = errno;
+ Perror(statp, stderr, "read(vc)", errno);
+- __res_iclose(statp, false);
+- return (0);
++ return close_and_return_error (statp, resplen2);
+ }
+ if (__glibc_unlikely (truncating)) {
+ /*
+@@ -1114,7 +1123,11 @@ send_dg(res_state statp,
retry_reopen:
retval = reopen (statp, terrno, ns);
if (retval <= 0)
retry:
evNowTime(&now);
evConsTime(&timeout, seconds, 0);
-@@ -1127,8 +1143,6 @@ send_dg(res_state statp,
+@@ -1127,8 +1140,6 @@ send_dg(res_state statp,
int recvresp2 = buf2 == NULL;
pfd[0].fd = EXT(statp).nssocks[ns];
pfd[0].events = POLLOUT;
wait:
if (need_recompute) {
recompute_resend:
-@@ -1136,9 +1150,7 @@ send_dg(res_state statp,
+@@ -1136,9 +1147,7 @@ send_dg(res_state statp,
if (evCmpTime(finish, now) <= 0) {
poll_err_out:
Perror(statp, stderr, "poll", errno);
}
evSubTime(&timeout, &finish, &now);
need_recompute = 0;
-@@ -1185,7 +1197,9 @@ send_dg(res_state statp,
+@@ -1185,7 +1194,9 @@ send_dg(res_state statp,
}
*gotsomewhere = 1;
}
if (n < 0) {
if (errno == EINTR)
-@@ -1253,7 +1267,7 @@ send_dg(res_state statp,
+@@ -1253,7 +1264,7 @@ send_dg(res_state statp,
fail_sendmmsg:
Perror(statp, stderr, "sendmmsg", errno);
}
}
else
-@@ -1271,7 +1285,7 @@ send_dg(res_state statp,
+@@ -1271,7 +1282,7 @@ send_dg(res_state statp,
if (errno == EINTR || errno == EAGAIN)
goto recompute_resend;
Perror(statp, stderr, "send", errno);
}
just_one:
if (nwritten != 0 || buf2 == NULL || single_request)
-@@ -1349,7 +1363,7 @@ send_dg(res_state statp,
+@@ -1349,7 +1360,7 @@ send_dg(res_state statp,
goto wait;
}
Perror(statp, stderr, "recvfrom", errno);
}
*gotsomewhere = 1;
if (__glibc_unlikely (*thisresplenp < HFIXEDSZ)) {
-@@ -1360,7 +1374,7 @@ send_dg(res_state statp,
+@@ -1360,7 +1371,7 @@ send_dg(res_state statp,
(stdout, ";; undersized: %d\n",
*thisresplenp));
*terrno = EMSGSIZE;
}
if ((recvresp1 || hp->id != anhp->id)
&& (recvresp2 || hp2->id != anhp->id)) {
-@@ -1409,7 +1423,7 @@ send_dg(res_state statp,
+@@ -1409,7 +1420,7 @@ send_dg(res_state statp,
? *thisanssizp : *thisresplenp);
/* record the error */
statp->_flags |= RES_F_EDNS0ERR;
}
#endif
if (!(statp->options & RES_INSECURE2)
-@@ -1461,10 +1475,10 @@ send_dg(res_state statp,
+@@ -1461,10 +1472,10 @@ send_dg(res_state statp,
goto wait;
}
}
if (anhp->rcode == NOERROR && anhp->ancount == 0
&& anhp->aa == 0 && anhp->ra == 0 && anhp->arcount == 0) {
-@@ -1486,6 +1500,8 @@ send_dg(res_state statp,
+@@ -1486,6 +1497,8 @@ send_dg(res_state statp,
__res_iclose(statp, false);
// XXX if we have received one reply we could
// XXX use it and not repeat it over TCP...
return (1);
}
/* Mark which reply we received. */
-@@ -1501,21 +1517,22 @@ send_dg(res_state statp,
+@@ -1501,21 +1514,22 @@ send_dg(res_state statp,
__res_iclose (statp, false);
retval = reopen (statp, terrno, ns);
if (retval <= 0)
else {
/* poll should not have returned > 0 in this case. */
abort ();
+diff --git a/stdio-common/printf_fp.c b/stdio-common/printf_fp.c
+index 4134f8a..baada9e 100644
+--- a/stdio-common/printf_fp.c
++++ b/stdio-common/printf_fp.c
+@@ -209,9 +209,9 @@ hack_digit (struct hack_digit_param *p)
+ }
+
+ int
+-___printf_fp (FILE *fp,
+- const struct printf_info *info,
+- const void *const *args)
++___printf_fp_l (FILE *fp, locale_t loc,
++ const struct printf_info *info,
++ const void *const *args)
+ {
+ /* The floating-point value to output. */
+ union
+@@ -263,18 +263,19 @@ ___printf_fp (FILE *fp,
+ /* Figure out the decimal point character. */
+ if (info->extra == 0)
+ {
+- decimal = _NL_CURRENT (LC_NUMERIC, DECIMAL_POINT);
+- decimalwc = _NL_CURRENT_WORD (LC_NUMERIC, _NL_NUMERIC_DECIMAL_POINT_WC);
++ decimal = _nl_lookup (loc, LC_NUMERIC, DECIMAL_POINT);
++ decimalwc = _nl_lookup_word
++ (loc, LC_NUMERIC, _NL_NUMERIC_DECIMAL_POINT_WC);
+ }
+ else
+ {
+- decimal = _NL_CURRENT (LC_MONETARY, MON_DECIMAL_POINT);
++ decimal = _nl_lookup (loc, LC_MONETARY, MON_DECIMAL_POINT);
+ if (*decimal == '\0')
+- decimal = _NL_CURRENT (LC_NUMERIC, DECIMAL_POINT);
+- decimalwc = _NL_CURRENT_WORD (LC_MONETARY,
++ decimal = _nl_lookup (loc, LC_NUMERIC, DECIMAL_POINT);
++ decimalwc = _nl_lookup_word (loc, LC_MONETARY,
+ _NL_MONETARY_DECIMAL_POINT_WC);
+ if (decimalwc == L'\0')
+- decimalwc = _NL_CURRENT_WORD (LC_NUMERIC,
++ decimalwc = _nl_lookup_word (loc, LC_NUMERIC,
+ _NL_NUMERIC_DECIMAL_POINT_WC);
+ }
+ /* The decimal point character must not be zero. */
+@@ -284,9 +285,9 @@ ___printf_fp (FILE *fp,
+ if (info->group)
+ {
+ if (info->extra == 0)
+- grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);
++ grouping = _nl_lookup (loc, LC_NUMERIC, GROUPING);
+ else
+- grouping = _NL_CURRENT (LC_MONETARY, MON_GROUPING);
++ grouping = _nl_lookup (loc, LC_MONETARY, MON_GROUPING);
+
+ if (*grouping <= 0 || *grouping == CHAR_MAX)
+ grouping = NULL;
+@@ -296,19 +297,20 @@ ___printf_fp (FILE *fp,
+ if (wide)
+ {
+ if (info->extra == 0)
+- thousands_sepwc =
+- _NL_CURRENT_WORD (LC_NUMERIC, _NL_NUMERIC_THOUSANDS_SEP_WC);
++ thousands_sepwc = _nl_lookup_word
++ (loc, LC_NUMERIC, _NL_NUMERIC_THOUSANDS_SEP_WC);
+ else
+ thousands_sepwc =
+- _NL_CURRENT_WORD (LC_MONETARY,
++ _nl_lookup_word (loc, LC_MONETARY,
+ _NL_MONETARY_THOUSANDS_SEP_WC);
+ }
+ else
+ {
+ if (info->extra == 0)
+- thousands_sep = _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP);
++ thousands_sep = _nl_lookup (loc, LC_NUMERIC, THOUSANDS_SEP);
+ else
+- thousands_sep = _NL_CURRENT (LC_MONETARY, MON_THOUSANDS_SEP);
++ thousands_sep = _nl_lookup
++ (loc, LC_MONETARY, MON_THOUSANDS_SEP);
+ }
+
+ if ((wide && thousands_sepwc == L'\0')
+@@ -1171,9 +1173,11 @@ ___printf_fp (FILE *fp,
+ size_t decimal_len;
+ size_t thousands_sep_len;
+ wchar_t *copywc;
+- size_t factor = (info->i18n
+- ? _NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_MB_CUR_MAX)
+- : 1);
++ size_t factor;
++ if (info->i18n)
++ factor = _nl_lookup_word (loc, LC_CTYPE, _NL_CTYPE_MB_CUR_MAX);
++ else
++ factor = 1;
+
+ decimal_len = strlen (decimal);
+
+@@ -1244,8 +1248,18 @@ ___printf_fp (FILE *fp,
+ }
+ return done;
+ }
++ldbl_hidden_def (___printf_fp_l, __printf_fp_l)
++ldbl_strong_alias (___printf_fp_l, __printf_fp_l)
++
++int
++___printf_fp (FILE *fp, const struct printf_info *info,
++ const void *const *args)
++{
++ return ___printf_fp_l (fp, _NL_CURRENT_LOCALE, info, args);
++}
+ ldbl_hidden_def (___printf_fp, __printf_fp)
+ ldbl_strong_alias (___printf_fp, __printf_fp)
++
+ \f
+ /* Return the number of extra grouping characters that will be inserted
+ into a number with INTDIG_MAX integer digits. */
+diff --git a/stdlib/Makefile b/stdlib/Makefile
+index 26fe67a..d978774 100644
+--- a/stdlib/Makefile
++++ b/stdlib/Makefile
+@@ -76,7 +76,7 @@ tests := tst-strtol tst-strtod testmb testrand testsort testdiv \
+ tst-secure-getenv tst-strtod-overflow tst-strtod-round \
+ tst-tininess tst-strtod-underflow tst-tls-atexit \
+ tst-setcontext3 tst-tls-atexit-nodelete \
+- tst-strtol-locale tst-strtod-nan-locale
++ tst-strtol-locale tst-strtod-nan-locale tst-strfmon_l
+ tests-static := tst-secure-getenv
+
+ modules-names = tst-tls-atexit-lib
+@@ -126,7 +126,8 @@ include ../Rules
+
+ ifeq ($(run-built-tests),yes)
+ LOCALES := cs_CZ.UTF-8 de_DE.UTF-8 en_US.ISO-8859-1 tr_TR.UTF-8 \
+- tr_TR.ISO-8859-9
++ tr_TR.ISO-8859-9 tg_TJ.UTF-8 te_IN.UTF-8 bn_IN.UTF-8 \
++ el_GR.UTF-8
+ include ../gen-locales.mk
+
+ $(objpfx)bug-strtod2.out: $(gen-locales)
+@@ -137,6 +138,7 @@ $(objpfx)tst-strtod4.out: $(gen-locales)
+ $(objpfx)tst-strtod5.out: $(gen-locales)
+ $(objpfx)tst-strtol-locale.out: $(gen-locales)
+ $(objpfx)tst-strtod-nan-locale.out: $(gen-locales)
++$(objpfx)tst-strfmon_l.out: $(gen-locales)
+ endif
+
+ # Testdir has to be named stdlib and needs to be writable
diff --git a/stdlib/setenv.c b/stdlib/setenv.c
index da61ee0..e66045f 100644
--- a/stdlib/setenv.c
UNLOCK;
+diff --git a/stdlib/strfmon_l.c b/stdlib/strfmon_l.c
+index b357020..5851a5b 100644
+--- a/stdlib/strfmon_l.c
++++ b/stdlib/strfmon_l.c
+@@ -68,9 +68,6 @@
+ #define _NL_CURRENT(category, item) \
+ (current->values[_NL_ITEM_INDEX (item)].string)
+
+-extern int __printf_fp (FILE *, const struct printf_info *,
+- const void *const *);
+-libc_hidden_proto (__printf_fp)
+ /* This function determines the number of digit groups in the output.
+ The definition is in printf_fp.c. */
+ extern unsigned int __guess_grouping (unsigned int intdig_max,
+@@ -532,7 +529,7 @@ __vstrfmon_l (char *s, size_t maxsize, __locale_t loc, const char *format,
+ info.extra = 1; /* This means use values from LC_MONETARY. */
+
+ ptr = &fpnum;
+- done = __printf_fp (&f._sbf._f, &info, &ptr);
++ done = __printf_fp_l (&f._sbf._f, loc, &info, &ptr);
+ if (done < 0)
+ return -1;
+
+diff --git a/stdlib/tst-strfmon_l.c b/stdlib/tst-strfmon_l.c
+new file mode 100644
+index 0000000..6841511
+--- /dev/null
++++ b/stdlib/tst-strfmon_l.c
+@@ -0,0 +1,220 @@
++/* Test locale dependence of strfmon_l.
++ Copyright (C) 2016 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, see
++ <http://www.gnu.org/licenses/>. */
++
++#include <stdbool.h>
++#include <stdio.h>
++#include <monetary.h>
++#include <string.h>
++#include <stdlib.h>
++#include <locale.h>
++
++static const char *const en_us_name = "en_US.ISO-8859-1";
++
++/* Locale value to be used by tests. */
++static locale_t loc;
++static const char *loc_name;
++
++/* Set the global locale to GLOBAL_NAME, and the locale referenced by
++ the loc variable above to LOCAL_NAME. */
++static void
++init_loc (const char *global_name, const char *local_name)
++{
++ loc = newlocale (LC_ALL_MASK, local_name, 0);
++ if (loc == 0)
++ {
++ printf ("error: newlocale (%s): %m\n", local_name);
++ abort ();
++ }
++ loc_name = local_name;
++
++ if (setlocale (LC_ALL, global_name) == NULL)
++ {
++ printf ("error: setlocale (%s): %m\n", global_name);
++ abort ();
++ }
++}
++
++/* Expected strings for a positive or negative value. */
++struct testcase
++{
++ const char *i; /* %i */
++ const char *n; /* %n */
++ const char *i_ungrouped; /* %^i */
++ const char *n_ungrouped; /* %^n */
++};
++
++/* Collected expected strings for both positive and negative
++ values. */
++struct testcase_pair
++{
++ struct testcase positive; /* 1234567.89 */
++ struct testcase negative; /* -1234567.89 */
++};
++
++static bool errors;
++
++/* Test one value using the locale loc. */
++static void
++test_one (const char *format, double value, const char *expected)
++{
++ static char actual[64];
++ int result = strfmon_l (actual, sizeof (actual), loc, format, value);
++ if (result < 0)
++ {
++ printf ("error: locale %s, format \"%s\", value %g: strfmon_l: %m\n",
++ loc_name, format, value);
++ errors = true;
++ }
++ else if (strcmp (actual, expected) != 0)
++ {
++ printf ("error: locale %s, format \"%s\", value %g: mismatch\n",
++ loc_name, format, value);
++ printf ("error: expected: \"%s\"\n", expected);
++ printf ("error: actual: \"%s\"\n", actual);
++ errors = true;
++ }
++}
++
++static void
++test_pair (const struct testcase_pair *pair)
++{
++ double positive = 1234567.89;
++ test_one ("%i", positive, pair->positive.i);
++ test_one ("%n", positive, pair->positive.n);
++ test_one ("%^i", positive, pair->positive.i_ungrouped);
++ test_one ("%^n", positive, pair->positive.n_ungrouped);
++ double negative = -1234567.89;
++ test_one ("%i", negative, pair->negative.i);
++ test_one ("%n", negative, pair->negative.n);
++ test_one ("%^i", negative, pair->negative.i_ungrouped);
++ test_one ("%^n", negative, pair->negative.n_ungrouped);
++}
++
++static const struct testcase_pair en_us =
++ {
++ {
++ "USD 1,234,567.89", "$1,234,567.89",
++ "USD 1234567.89", "$1234567.89"
++ },
++ {
++ "-USD 1,234,567.89", "-$1,234,567.89",
++ "-USD 1234567.89", "-$1234567.89"
++ }
++ };
++
++static void
++test_en_us (const char *other_name)
++{
++ init_loc (other_name, en_us_name);
++ test_pair (&en_us);
++ freelocale (loc);
++}
++
++struct locale_pair
++{
++ const char *locale_name;
++ struct testcase_pair pair;
++};
++
++static const struct locale_pair tests[] =
++ {
++ {
++ "de_DE.UTF-8",
++ {
++ {
++ "1.234.567,89 EUR", "1.234.567,89 \u20ac",
++ "1234567,89 EUR", "1234567,89 \u20ac"
++ },
++ {
++ "-1.234.567,89 EUR", "-1.234.567,89 \u20ac",
++ "-1234567,89 EUR", "-1234567,89 \u20ac"
++ }
++ },
++ },
++ {
++ "tg_TJ.UTF-8",
++ {
++ {
++ "1 234 567.89 TJS", "1 234 567.89 \u0440\u0443\u0431",
++ "1234567.89 TJS", "1234567.89 \u0440\u0443\u0431"
++ },
++ {
++ "-1 234 567.89 TJS", "-1 234 567.89 \u0440\u0443\u0431",
++ "-1234567.89 TJS", "-1234567.89 \u0440\u0443\u0431"
++ }
++ }
++ },
++ {
++ "te_IN.UTF-8",
++ {
++ {
++ "INR12,34,567.89", "\u20b912,34,567.89",
++ "INR1234567.89", "\u20b91234567.89"
++ },
++ {
++ "-INR12,34,567.89", "-\u20b912,34,567.89",
++ "-INR1234567.89", "-\u20b91234567.89"
++ }
++ }
++ },
++ {
++ "bn_IN.UTF-8",
++ {
++ {
++ "INR 12,345,67.89", "\u20b9 12,345,67.89",
++ "INR 1234567.89", "\u20b9 1234567.89"
++ },
++ {
++ "-INR 12,345,67.89", "-\u20b9 12,345,67.89",
++ "-INR 1234567.89", "-\u20b9 1234567.89"
++ }
++ }
++ },
++ {
++ "el_GR.UTF-8",
++ {
++ {
++ "1.234.567,89EUR", "1.234.567,89\u20ac",
++ "1234567,89EUR", "1234567,89\u20ac"
++ },
++ {
++ "-EUR1.234.567,89", "-\u20ac1.234.567,89",
++ "-EUR1234567,89", "-\u20ac1234567,89",
++ }
++ }
++ },
++ {}
++ };
++
++static int
++do_test (void)
++{
++ for (const struct locale_pair *test = tests;
++ test->locale_name != NULL; ++test)
++ {
++ init_loc (en_us_name, test->locale_name);
++ test_pair (&test->pair);
++ freelocale (loc);
++ test_en_us (test->locale_name);
++ }
++
++ return errors;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
diff --git a/sysdeps/arm/nacl/libc.abilist b/sysdeps/arm/nacl/libc.abilist
index 561441e..0560510 100644
--- a/sysdeps/arm/nacl/libc.abilist
+GLIBC_2.23 fts64_open F
+GLIBC_2.23 fts64_read F
+GLIBC_2.23 fts64_set F
+diff --git a/sysdeps/generic/malloc-machine.h b/sysdeps/generic/malloc-machine.h
+index 1ed2d50..71b95c2 100644
+--- a/sysdeps/generic/malloc-machine.h
++++ b/sysdeps/generic/malloc-machine.h
+@@ -22,25 +22,6 @@
+
+ #include <atomic.h>
+
+-#ifndef mutex_init /* No threads, provide dummy macros */
+-
+-# define NO_THREADS
+-
+-/* The mutex functions used to do absolutely nothing, i.e. lock,
+- trylock and unlock would always just return 0. However, even
+- without any concurrently active threads, a mutex can be used
+- legitimately as an `in use' flag. To make the code that is
+- protected by a mutex async-signal safe, these macros would have to
+- be based on atomic test-and-set operations, for example. */
+-typedef int mutex_t;
+-
+-# define mutex_init(m) (*(m) = 0)
+-# define mutex_lock(m) ({ *(m) = 1; 0; })
+-# define mutex_trylock(m) (*(m) ? 1 : ((*(m) = 1), 0))
+-# define mutex_unlock(m) (*(m) = 0)
+-
+-#endif /* !defined mutex_init */
+-
+ #ifndef atomic_full_barrier
+ # define atomic_full_barrier() __asm ("" ::: "memory")
+ #endif
diff --git a/sysdeps/i386/configure b/sysdeps/i386/configure
index 9515719..5b55c5a 100644
--- a/sysdeps/i386/configure
jz 2f
LOAD_FUNC_GOT_EAX (__memset_chk_sse2_rep)
2: ret
+diff --git a/sysdeps/mach/hurd/fork.c b/sysdeps/mach/hurd/fork.c
+index ad09fd7..2e8b59e 100644
+--- a/sysdeps/mach/hurd/fork.c
++++ b/sysdeps/mach/hurd/fork.c
+@@ -26,6 +26,7 @@
+ #include <assert.h>
+ #include "hurdmalloc.h" /* XXX */
+ #include <tls.h>
++#include <malloc/malloc-internal.h>
+
+ #undef __fork
+
+@@ -107,6 +108,12 @@ __fork (void)
+ /* Run things that prepare for forking before we create the task. */
+ RUN_HOOK (_hurd_fork_prepare_hook, ());
+
++ /* Acquire malloc locks. This needs to come last because fork
++ handlers may use malloc, and the libio list lock has an
++ indirect malloc dependency as well (via the getdelim
++ function). */
++ __malloc_fork_lock_parent ();
++
+ /* Lock things that want to be locked before we fork. */
+ {
+ void *const *p;
+@@ -604,6 +611,9 @@ __fork (void)
+ nthreads * sizeof (*threads));
+ }
+
++ /* Release malloc locks. */
++ __malloc_fork_unlock_parent ();
++
+ /* Run things that want to run in the parent to restore it to
+ normality. Usually prepare hooks and parent hooks are
+ symmetrical: the prepare hook arrests state in some way for the
+@@ -655,6 +665,9 @@ __fork (void)
+ /* Forking clears the trace flag. */
+ __sigemptyset (&_hurdsig_traced);
+
++ /* Release malloc locks. */
++ __malloc_fork_unlock_child ();
++
+ /* Run things that want to run in the child task to set up. */
+ RUN_HOOK (_hurd_fork_child_hook, ());
+
+diff --git a/sysdeps/nptl/fork.c b/sysdeps/nptl/fork.c
+index 27f8d52..1a68cbd 100644
+--- a/sysdeps/nptl/fork.c
++++ b/sysdeps/nptl/fork.c
+@@ -31,7 +31,7 @@
+ #include <fork.h>
+ #include <arch-fork.h>
+ #include <futex-internal.h>
+-
++#include <malloc/malloc-internal.h>
+
+ static void
+ fresetlockfiles (void)
+@@ -111,6 +111,11 @@ __libc_fork (void)
+
+ _IO_list_lock ();
+
++ /* Acquire malloc locks. This needs to come last because fork
++ handlers may use malloc, and the libio list lock has an indirect
++ malloc dependency as well (via the getdelim function). */
++ __malloc_fork_lock_parent ();
++
+ #ifndef NDEBUG
+ pid_t ppid = THREAD_GETMEM (THREAD_SELF, tid);
+ #endif
+@@ -168,6 +173,9 @@ __libc_fork (void)
+ # endif
+ #endif
+
++ /* Release malloc locks. */
++ __malloc_fork_unlock_child ();
++
+ /* Reset the file list. These are recursive mutexes. */
+ fresetlockfiles ();
+
+@@ -209,6 +217,9 @@ __libc_fork (void)
+ /* Restore the PID value. */
+ THREAD_SETMEM (THREAD_SELF, pid, parentpid);
+
++ /* Release malloc locks, parent process variant. */
++ __malloc_fork_unlock_parent ();
++
+ /* We execute this even if the 'fork' call failed. */
+ _IO_list_unlock ();
+
diff --git a/sysdeps/s390/bits/link.h b/sysdeps/s390/bits/link.h
index 2ef7f44..e27ed67 100644
--- a/sysdeps/s390/bits/link.h
+ cfi_endproc
+ .size _dl_runtime_profile, .-_dl_runtime_profile
+#endif
+diff --git a/sysdeps/unix/sysv/linux/i386/glob64.c b/sysdeps/unix/sysv/linux/i386/glob64.c
+index b4fcd1a..802c957 100644
+--- a/sysdeps/unix/sysv/linux/i386/glob64.c
++++ b/sysdeps/unix/sysv/linux/i386/glob64.c
+@@ -1,3 +1,21 @@
++/* Two glob variants with 64-bit support, for dirent64 and __olddirent64.
++ Copyright (C) 1998-2016 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, see
++ <http://www.gnu.org/licenses/>. */
++
+ #include <dirent.h>
+ #include <glob.h>
+ #include <sys/stat.h>
+@@ -38,11 +56,15 @@ int __old_glob64 (const char *__pattern, int __flags,
+
+ #undef dirent
+ #define dirent __old_dirent64
++#undef GL_READDIR
++# define GL_READDIR(pglob, stream) \
++ ((struct __old_dirent64 *) (pglob)->gl_readdir (stream))
+ #undef __readdir
+ #define __readdir(dirp) __old_readdir64 (dirp)
+ #undef glob
+ #define glob(pattern, flags, errfunc, pglob) \
+ __old_glob64 (pattern, flags, errfunc, pglob)
++#define convert_dirent __old_convert_dirent
+ #define glob_in_dir __old_glob_in_dir
+ #define GLOB_ATTRIBUTE attribute_compat_text_section
+
diff --git a/sysdeps/unix/sysv/linux/mips/makecontext.S b/sysdeps/unix/sysv/linux/mips/makecontext.S
index 66600c7..3196554 100644
--- a/sysdeps/unix/sysv/linux/mips/makecontext.S
/* Enable inline functions only for i486 or better when compiling for
ia32. */
#if !defined __x86_64__ && (defined __i486__ || defined __pentium__ \
+diff --git a/sysdeps/x86_64/Makefile b/sysdeps/x86_64/Makefile
+index 67ed5ba..cc47b88 100644
+--- a/sysdeps/x86_64/Makefile
++++ b/sysdeps/x86_64/Makefile
+@@ -60,7 +60,7 @@ $(objpfx)tst-audit3: $(objpfx)tst-auditmod3a.so
+ $(objpfx)tst-audit3.out: $(objpfx)tst-auditmod3b.so
+ tst-audit3-ENV = LD_AUDIT=$(objpfx)tst-auditmod3b.so
+
+-$(objpfx)tst-audit4: $(objpfx)tst-auditmod4a.so
++$(objpfx)tst-audit4: $(objpfx)tst-audit4-aux.o $(objpfx)tst-auditmod4a.so
+ $(objpfx)tst-audit4.out: $(objpfx)tst-auditmod4b.so
+ tst-audit4-ENV = LD_AUDIT=$(objpfx)tst-auditmod4b.so
+
+@@ -77,12 +77,12 @@ $(objpfx)tst-audit7: $(objpfx)tst-auditmod7a.so
+ $(objpfx)tst-audit7.out: $(objpfx)tst-auditmod7b.so
+ tst-audit7-ENV = LD_AUDIT=$(objpfx)tst-auditmod7b.so
+
+-$(objpfx)tst-audit10: $(objpfx)tst-auditmod10a.so
++$(objpfx)tst-audit10: $(objpfx)tst-audit10-aux.o $(objpfx)tst-auditmod10a.so
+ $(objpfx)tst-audit10.out: $(objpfx)tst-auditmod10b.so
+ tst-audit10-ENV = LD_AUDIT=$(objpfx)tst-auditmod10b.so
+
+ AVX-CFLAGS=-mavx -mno-vzeroupper
+-CFLAGS-tst-audit4.c += $(AVX-CFLAGS)
++CFLAGS-tst-audit4-aux.c += $(AVX-CFLAGS)
+ CFLAGS-tst-auditmod4a.c += $(AVX-CFLAGS)
+ CFLAGS-tst-auditmod4b.c += $(AVX-CFLAGS)
+ CFLAGS-tst-auditmod6b.c += $(AVX-CFLAGS)
+@@ -90,7 +90,7 @@ CFLAGS-tst-auditmod6c.c += $(AVX-CFLAGS)
+ CFLAGS-tst-auditmod7b.c += $(AVX-CFLAGS)
+ ifeq (yes,$(config-cflags-avx512))
+ AVX512-CFLAGS = -mavx512f
+-CFLAGS-tst-audit10.c += $(AVX512-CFLAGS)
++CFLAGS-tst-audit10-aux.c += $(AVX512-CFLAGS)
+ CFLAGS-tst-auditmod10a.c += $(AVX512-CFLAGS)
+ CFLAGS-tst-auditmod10b.c += $(AVX512-CFLAGS)
+ endif
diff --git a/sysdeps/x86_64/configure b/sysdeps/x86_64/configure
index c72b9d3..88fbfe4 100644
--- a/sysdeps/x86_64/configure
mov %RBX_LP, %RSP_LP
cfi_def_cfa_register(%rsp)
movq (%rsp), %rbx
+diff --git a/sysdeps/x86_64/tst-audit10-aux.c b/sysdeps/x86_64/tst-audit10-aux.c
+new file mode 100644
+index 0000000..992a16c
+--- /dev/null
++++ b/sysdeps/x86_64/tst-audit10-aux.c
+@@ -0,0 +1,41 @@
++/* Test case for preserved AVX512 registers in dynamic linker, -mavx512f part.
++ Copyright (C) 2012-2016 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, see
++ <http://www.gnu.org/licenses/>. */
++
++#include <immintrin.h>
++#include <stdlib.h>
++#include <string.h>
++
++int
++tst_audit10_aux (void)
++{
++#ifdef __AVX512F__
++ extern __m512i audit_test (__m512i, __m512i, __m512i, __m512i,
++ __m512i, __m512i, __m512i, __m512i);
++
++ __m512i zmm = _mm512_setzero_si512 ();
++ __m512i ret = audit_test (zmm, zmm, zmm, zmm, zmm, zmm, zmm, zmm);
++
++ zmm = _mm512_set1_epi64 (0x12349876);
++
++ if (memcmp (&zmm, &ret, sizeof (ret)))
++ abort ();
++ return 0;
++#else /* __AVX512F__ */
++ return 77;
++#endif /* __AVX512F__ */
++}
+diff --git a/sysdeps/x86_64/tst-audit10.c b/sysdeps/x86_64/tst-audit10.c
+index d104341..0df2275 100644
+--- a/sysdeps/x86_64/tst-audit10.c
++++ b/sysdeps/x86_64/tst-audit10.c
+@@ -1,4 +1,5 @@
+-/* Copyright (C) 2012-2016 Free Software Foundation, Inc.
++/* Test case for preserved AVX512 registers in dynamic linker.
++ Copyright (C) 2012-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
+@@ -15,17 +16,14 @@
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+-/* Test case for x86-64 preserved registers in dynamic linker. */
+-
+-#ifdef __AVX512F__
+-#include <stdlib.h>
+-#include <string.h>
+ #include <cpuid.h>
+-#include <immintrin.h>
++
++int tst_audit10_aux (void);
+
+ static int
+ avx512_enabled (void)
+ {
++#ifdef bit_AVX512F
+ unsigned int eax, ebx, ecx, edx;
+
+ if (__get_cpuid (1, &eax, &ebx, &ecx, &edx) == 0
+@@ -40,34 +38,20 @@ avx512_enabled (void)
+
+ /* Verify that ZMM, YMM and XMM states are enabled. */
+ return (eax & 0xe6) == 0xe6;
++#else
++ return 0;
++#endif
+ }
+
+-
+-extern __m512i audit_test (__m512i, __m512i, __m512i, __m512i,
+- __m512i, __m512i, __m512i, __m512i);
+ static int
+ do_test (void)
+ {
+ /* Run AVX512 test only if AVX512 is supported. */
+ if (avx512_enabled ())
+- {
+- __m512i zmm = _mm512_setzero_si512 ();
+- __m512i ret = audit_test (zmm, zmm, zmm, zmm, zmm, zmm, zmm, zmm);
+-
+- zmm = _mm512_set1_epi64 (0x12349876);
+-
+- if (memcmp (&zmm, &ret, sizeof (ret)))
+- abort ();
+- }
+- return 0;
+-}
+-#else
+-static int
+-do_test (void)
+-{
+- return 0;
++ return tst_audit10_aux ();
++ else
++ return 77;
+ }
+-#endif
+
+ #define TEST_FUNCTION do_test ()
+ #include "../../test-skeleton.c"
+diff --git a/sysdeps/x86_64/tst-audit4-aux.c b/sysdeps/x86_64/tst-audit4-aux.c
+new file mode 100644
+index 0000000..a1aeb65
+--- /dev/null
++++ b/sysdeps/x86_64/tst-audit4-aux.c
+@@ -0,0 +1,39 @@
++/* Test case for preserved AVX registers in dynamic linker, -mavx part.
++ Copyright (C) 2009-2016 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, see
++ <http://www.gnu.org/licenses/>. */
++
++#include <immintrin.h>
++#include <stdlib.h>
++#include <string.h>
++
++extern __m256i audit_test (__m256i, __m256i, __m256i, __m256i,
++ __m256i, __m256i, __m256i, __m256i);
++
++int
++tst_audit4_aux (void)
++{
++#ifdef __AVX__
++ __m256i ymm = _mm256_setzero_si256 ();
++ __m256i ret = audit_test (ymm, ymm, ymm, ymm, ymm, ymm, ymm, ymm);
++ ymm = _mm256_set1_epi32 (0x12349876);
++ if (memcmp (&ymm, &ret, sizeof (ret)))
++ abort ();
++ return 0;
++#else /* __AVX__ */
++ return 77;
++#endif /* __AVX__ */
++}
+diff --git a/sysdeps/x86_64/tst-audit4.c b/sysdeps/x86_64/tst-audit4.c
+index 44d5123..d8e2ab1 100644
+--- a/sysdeps/x86_64/tst-audit4.c
++++ b/sysdeps/x86_64/tst-audit4.c
+@@ -1,11 +1,24 @@
+-/* Test case for x86-64 preserved registers in dynamic linker. */
++/* Test case for preserved AVX registers in dynamic linker.
++ Copyright (C) 2009-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/>. */
+
+-#ifdef __AVX__
+-#include <stdlib.h>
+-#include <string.h>
+ #include <cpuid.h>
+-#include <immintrin.h>
+
++int tst_audit4_aux (void);
+
+ static int
+ avx_enabled (void)
+@@ -22,31 +35,15 @@ avx_enabled (void)
+ return (eax & 6) == 6;
+ }
+
+-
+-extern __m256i audit_test (__m256i, __m256i, __m256i, __m256i,
+- __m256i, __m256i, __m256i, __m256i);
+ static int
+ do_test (void)
+ {
+ /* Run AVX test only if AVX is supported. */
+ if (avx_enabled ())
+- {
+- __m256i ymm = _mm256_setzero_si256 ();
+- __m256i ret = audit_test (ymm, ymm, ymm, ymm, ymm, ymm, ymm, ymm);
+-
+- ymm = _mm256_set1_epi32 (0x12349876);
+- if (memcmp (&ymm, &ret, sizeof (ret)))
+- abort ();
+- }
+- return 0;
+-}
+-#else
+-static int
+-do_test (void)
+-{
+- return 0;
++ return tst_audit4_aux ();
++ else
++ return 77;
+ }
+-#endif
+
+ #define TEST_FUNCTION do_test ()
+ #include "../../test-skeleton.c"