This is an automated email from the git hooks/post-receive script.

aurel32 pushed a commit to branch sid
in repository glibc.

commit edb4b06a022b194efbf1b7b3a72e2de1cb302035
Author: Aurelien Jarno <aurel...@aurel32.net>
Date:   Sat Dec 2 11:05:46 2017 +0100

    debian/patches/git-updates.diff: update from upstream stable branch:
    
    * debian/patches/git-updates.diff: update from upstream stable branch:
      - Fix buffer overflow in glob with GLOB_TILDE (CVE-2017-15670).  Closes:
        #879501.
      - Fix memory leak in glob with GLOB_TILDE (CVE-2017-15671).  Closes:
        #879500.
      - Fix a buffer overflow in glob with GLOB_TILDE in unescaping
        (CVE-2017-15804).  Closes: #879955.
---
 debian/changelog                |    6 +
 debian/patches/git-updates.diff | 2486 +++++++++++++++++++++++++++++++++++++--
 2 files changed, 2393 insertions(+), 99 deletions(-)

diff --git a/debian/changelog b/debian/changelog
index d133153..e072fe9 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -5,6 +5,12 @@ glibc (2.25-3) UNRELEASED; urgency=medium
     - Fix assertion failure in posix_spawn().  Closes: #882794.
     - Fix missing posix_fadvise64 from static mips64el build. Closes:
       #883186.
+    - Fix buffer overflow in glob with GLOB_TILDE (CVE-2017-15670).  Closes:
+      #879501.
+    - Fix memory leak in glob with GLOB_TILDE (CVE-2017-15671).  Closes:
+      #879500.
+    - Fix a buffer overflow in glob with GLOB_TILDE in unescaping
+      (CVE-2017-15804).  Closes: #879955.
   * debian/patches/any/local-dlfptr.diff: remove, it's not used anymore by
     HPPA and causes issues on IA64.  Closes: #882874.
   * debian/patches/submitted-ldconfig-c-collation.diff: New patch to process
diff --git a/debian/patches/git-updates.diff b/debian/patches/git-updates.diff
index 93e71d6..17a99ed 100644
--- a/debian/patches/git-updates.diff
+++ b/debian/patches/git-updates.diff
@@ -1,10 +1,104 @@
 GIT update of git://sourceware.org/git/glibc.git/release/2.25/master from 
glibc-2.25
 
 diff --git a/ChangeLog b/ChangeLog
-index f140ee67de..ad563057d3 100644
+index f140ee67de..f85bf022b9 100644
 --- a/ChangeLog
 +++ b/ChangeLog
-@@ -1,3 +1,615 @@
+@@ -1,3 +1,709 @@
++2017-11-02  Florian Weimer  <fwei...@redhat.com>
++
++      [BZ #22332]
++      * posix/tst-glob-tilde.c (do_noescape): New variable.
++      (one_test): Process it.
++      (do_test): Set do_noescape.  Add unescaping test case.
++
++2017-10-22  Paul Eggert <egg...@cs.ucla.edu>
++
++      [BZ #22332]
++      * posix/glob.c (__glob): Fix buffer overflow during GLOB_TILDE
++      unescaping.
++
++2017-10-21  Florian Weimer  <fwei...@redhat.com>
++
++      * posix/Makefile (tests): Add tst-glob-tilde.
++      (tests-special): Add tst-glob-tilde-mem.out
++      (tst-glob-tilde-ENV): Set MALLOC_TRACE.
++      (tst-glob-tilde-mem.out): Add mtrace check.
++      * posix/tst-glob-tilde.c: New file.
++
++2017-10-20  Paul Eggert <egg...@cs.ucla.edu>
++
++      [BZ #22320]
++      CVE-2017-15670
++      * posix/glob.c (__glob): Fix one-byte overflow.
++
++2017-09-08  Adhemerval Zanella  <adhemerval.zane...@linaro.org>
++
++      [BZ #1062]
++      CVE-2017-15671
++      * posix/Makefile (routines): Add globfree, globfree64, and
++      glob_pattern_p.
++      * posix/flexmember.h: New file.
++      * posix/glob_internal.h: Likewise.
++      * posix/glob_pattern_p.c: Likewise.
++      * posix/globfree.c: Likewise.
++      * posix/globfree64.c: Likewise.
++      * sysdeps/gnu/globfree64.c: Likewise.
++      * sysdeps/unix/sysv/linux/alpha/globfree.c: Likewise.
++      * sysdeps/unix/sysv/linux/mips/mips64/n64/globfree64.c: Likewise.
++      * sysdeps/unix/sysv/linux/oldglob.c: Likewise.
++      * sysdeps/unix/sysv/linux/wordsize-64/globfree64.c: Likewise.
++      * sysdeps/unix/sysv/linux/x86_64/x32/globfree.c: Likewise.
++      * sysdeps/wordsize-64/globfree.c: Likewise.
++      * sysdeps/wordsize-64/globfree64.c: Likewise.
++      * posix/glob.c (HAVE_CONFIG_H): Use !_LIBC instead.
++      [NDEBUG): Remove comments.
++      (GLOB_ONLY_P, _AMIGA, VMS): Remove define.
++      (dirent_type): New type.  Use uint_fast8_t not
++      uint8_t, as C99 does not require uint8_t.
++      (DT_UNKNOWN, DT_DIR, DT_LNK): New macros.
++      (struct readdir_result): Use dirent_type.  Do not define skip_entry
++      unless it is needed; this saves a byte on platforms lacking d_ino.
++      (readdir_result_type, readdir_result_skip_entry):
++      New functions, replacing ...
++      (readdir_result_might_be_symlink, readdir_result_might_be_dir):
++       these functions, which were removed.  This makes the callers
++      easier to read.  All callers changed.
++      (D_INO_TO_RESULT): Now empty if there is no d_ino.
++      (size_add_wrapv, glob_use_alloca): New static functions.
++      (glob, glob_in_dir): Check for size_t overflow in several places,
++      and fix some size_t checks that were not quite right.
++      Remove old code using SHELL since Bash no longer
++      uses this.
++      (glob, prefix_array): Separate MS code better.
++      (glob_in_dir): Remove old Amiga and VMS code.
++      (globfree, __glob_pattern_type, __glob_pattern_p): Move to
++      separate files.
++      (glob_in_dir): Do not rely on undefined behavior in accessing
++      struct members beyond their bounds.  Use a flexible array member
++      instead
++      (link_stat): Rename from link_exists2_p and return -1/0 instead of
++      0/1.  Caller changed.
++      (glob): Fix memory leaks.
++      * posix/glob64 (globfree64): Move to separate file.
++      * sysdeps/gnu/glob64.c (NO_GLOB_PATTERN_P): Remove define.
++      (globfree64): Remove hidden alias.
++      * sysdeps/unix/sysv/linux/Makefile (sysdeps_routines): Add
++      oldglob.
++      * sysdeps/unix/sysv/linux/alpha/glob.c (__new_globfree): Move to
++      separate file.
++      * sysdeps/unix/sysv/linux/i386/glob64.c (NO_GLOB_PATTERN_P): Remove
++      define.
++      Move compat code to separate file.
++      * sysdeps/wordsize-64/glob.c (globfree): Move definitions to
++      separate file.
++
++2017-08-20  H.J. Lu  <hongjiu...@intel.com>
++
++      [BZ #18822]
++      * sysdeps/unix/sysv/linux/i386/glob64.c (__old_glob64): Add
++      libc_hidden_proto and libc_hidden_def.
++
 +2017-03-14  Adhemerval Zanella  <adhemerval.zane...@linaro.org>
 +
 +      [BZ #21232]
@@ -724,10 +818,10 @@ index e9194e54cf..43343f03ee 100644
        | sed -n -f $< > $@.new
        test -s $@.new
 diff --git a/NEWS b/NEWS
-index ec15dde761..1879b735e6 100644
+index ec15dde761..0a8f20e371 100644
 --- a/NEWS
 +++ b/NEWS
-@@ -5,6 +5,31 @@ See the end for copying conditions.
+@@ -5,6 +5,47 @@ See the end for copying conditions.
  Please send GNU C library bug reports via <http://sourceware.org/bugzilla/>
  using `glibc' in the "product" field.
  
@@ -738,6 +832,15 @@ index ec15dde761..1879b735e6 100644
 +* The DNS stub resolver limits the advertised UDP buffer size to 1200 bytes,
 +  to avoid fragmentation-based spoofing attacks.
 +
++  CVE-2017-15671: The glob function, when invoked with GLOB_TILDE,
++  would sometimes fail to free memory allocated during ~ operator
++  processing, leading to a memory leak and, potentially, to a denial
++  of service.
++
++  CVE-2017-15804: The glob function, when invoked with GLOB_TILDE and
++  without GLOB_NOESCAPE, could write past the end of a buffer while
++  unescaping user names.  Reported by Tim Rühsen.
++
 +The following bugs are resolved with this release:
 +
 +  [20257] sunrpc: clntudp_call does not enforce timeout when receiving data
@@ -755,6 +858,13 @@ index ec15dde761..1879b735e6 100644
 +  [21778] Robust mutex may deadlock
 +  [21972] assert macro requires operator== (int) for its argument type
 +  [22322] libc: [mips64] wrong bits/long-double.h installed
++
++Security related changes:
++
++  CVE-2017-15670: The glob function, when invoked with GLOB_TILDE, suffered
++  from a one-byte overflow during ~ operator processing (either on the stack
++  or the heap, depending on the length of the user name).
++
 +
  Version 2.25
  
@@ -3072,17 +3182,1827 @@ index 0000000000..8221a61d29
 +#include "tst-mutex7.c"
 diff --git a/nptl/tst-rwlock20.c b/nptl/tst-rwlock20.c
 new file mode 100644
-index 0000000000..4aeea2b8f5
+index 0000000000..4aeea2b8f5
+--- /dev/null
++++ b/nptl/tst-rwlock20.c
+@@ -0,0 +1,116 @@
++/* Test program for a read-phase / write-phase explicit hand-over.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public License as
++   published by the Free Software Foundation; either version 2.1 of the
++   License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; see the file COPYING.LIB.  If
++   not, see <http://www.gnu.org/licenses/>.  */
++
++#include <errno.h>
++#include <error.h>
++#include <pthread.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <stdint.h>
++#include <time.h>
++#include <atomic.h>
++#include <support/xthread.h>
++
++/* We realy want to set threads to 2 to reproduce this issue. The goal
++   is to have one primary writer and a single reader, and to hit the
++   bug that happens in the interleaving of those two phase transitions.
++   However, on most hardware, adding a second writer seems to help the
++   interleaving happen slightly more often, say 20% of the time.  On a
++   16 core ppc64 machine this fails 100% of the time with an unpatched
++   glibc.  On a 8 core x86_64 machine this fails ~93% of the time, but
++   it doesn't fail at all on a 4 core system, so having available
++   unloaded cores makes a big difference in reproducibility.  On an 8
++   core qemu/kvm guest the reproducer reliability drops to ~10%.  */
++#define THREADS 3
++
++#define KIND PTHREAD_RWLOCK_PREFER_READER_NP
++
++static pthread_rwlock_t lock;
++static int done = 0;
++
++static void*
++tf (void* arg)
++{
++  while (atomic_load_relaxed (&done) == 0)
++    {
++      int rcnt = 0;
++      int wcnt = 100;
++      if ((uintptr_t) arg == 0)
++      {
++        rcnt = 1;
++        wcnt = 1;
++      }
++
++      do
++      {
++        if (wcnt)
++          {
++            xpthread_rwlock_wrlock (&lock);
++            xpthread_rwlock_unlock (&lock);
++            wcnt--;
++        }
++        if (rcnt)
++          {
++            xpthread_rwlock_rdlock (&lock);
++            xpthread_rwlock_unlock (&lock);
++            rcnt--;
++        }
++      }
++      while ((atomic_load_relaxed (&done) == 0) && (rcnt + wcnt > 0));
++
++    }
++    return NULL;
++}
++
++
++
++static int
++do_test (void)
++{
++  pthread_t thr[THREADS];
++  int n;
++  pthread_rwlockattr_t attr;
++
++  xpthread_rwlockattr_init (&attr);
++  xpthread_rwlockattr_setkind_np (&attr, KIND);
++
++  xpthread_rwlock_init (&lock, &attr);
++
++  /* Make standard error the same as standard output.  */
++  dup2 (1, 2);
++
++  /* Make sure we see all message, even those on stdout.  */
++  setvbuf (stdout, NULL, _IONBF, 0);
++
++  for (n = 0; n < THREADS; ++n)
++    thr[n] = xpthread_create (NULL, tf, (void *) (uintptr_t) n);
++
++  struct timespec delay;
++  delay.tv_sec = 10;
++  delay.tv_nsec = 0;
++  nanosleep (&delay, NULL);
++  atomic_store_relaxed (&done, 1);
++
++  /* Wait for all the threads.  */
++  for (n = 0; n < THREADS; ++n)
++    xpthread_join (thr[n]);
++
++  return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/posix/Makefile b/posix/Makefile
+index 8f23d647c8..ccbfcf3c48 100644
+--- a/posix/Makefile
++++ b/posix/Makefile
+@@ -43,7 +43,7 @@ routines :=                                                  
              \
+       getpgid setpgid getpgrp bsd-getpgrp setpgrp getsid setsid             \
+       getresuid getresgid setresuid setresgid                               \
+       pathconf sysconf fpathconf                                            \
+-      glob glob64 fnmatch regex                                             \
++      glob glob64 globfree globfree64 glob_pattern_p fnmatch regex          \
+       confstr                                                               \
+       getopt getopt1 getopt_init                                            \
+       sched_setp sched_getp sched_sets sched_gets sched_yield sched_primax  \
+@@ -91,7 +91,8 @@ tests                := tstgetopt testfnm runtests runptests 
     \
+                  tst-pathconf tst-getaddrinfo4 tst-rxspencer-no-utf8 \
+                  tst-fnmatch3 bug-regex36 tst-getaddrinfo5 \
+                  tst-posix_spawn-fd \
+-                 tst-posix_fadvise tst-posix_fadvise64
++                 tst-posix_fadvise tst-posix_fadvise64 \
++                 tst-glob-tilde
+ xtests                := bug-ga2
+ ifeq (yes,$(build-shared))
+ test-srcs     := globtest
+@@ -134,7 +135,8 @@ tests-special += $(objpfx)bug-regex2-mem.out 
$(objpfx)bug-regex14-mem.out \
+                $(objpfx)tst-rxspencer-no-utf8-mem.out 
$(objpfx)tst-pcre-mem.out \
+                $(objpfx)tst-boost-mem.out $(objpfx)tst-getconf.out \
+                $(objpfx)bug-glob2-mem.out $(objpfx)tst-vfork3-mem.out \
+-               $(objpfx)tst-fnmatch-mem.out $(objpfx)bug-regex36-mem.out
++               $(objpfx)tst-fnmatch-mem.out $(objpfx)bug-regex36-mem.out \
++               $(objpfx)tst-glob-tilde-mem.out
+ xtests-special += $(objpfx)bug-ga2-mem.out
+ endif
+ 
+@@ -341,6 +343,12 @@ $(objpfx)bug-glob2-mem.out: $(objpfx)bug-glob2.out
+       $(common-objpfx)malloc/mtrace $(objpfx)bug-glob2.mtrace > $@; \
+       $(evaluate-test)
+ 
++tst-glob-tilde-ENV = MALLOC_TRACE=$(objpfx)tst-glob-tilde.mtrace
++
++$(objpfx)tst-glob-tilde-mem.out: $(objpfx)tst-glob-tilde.out
++      $(common-objpfx)malloc/mtrace $(objpfx)tst-glob-tilde.mtrace > $@; \
++      $(evaluate-test)
++
+ $(inst_libexecdir)/getconf: $(inst_bindir)/getconf \
+                           $(objpfx)getconf.speclist FORCE
+       $(addprefix $(..)./scripts/mkinstalldirs ,\
+diff --git a/posix/flexmember.h b/posix/flexmember.h
+new file mode 100644
+index 0000000000..107c1f09e9
+--- /dev/null
++++ b/posix/flexmember.h
+@@ -0,0 +1,45 @@
++/* Sizes of structs with flexible array members.
++
++   Copyright 2016-2017 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/>.
++
++   Written by Paul Eggert.  */
++
++#include <stddef.h>
++
++/* Nonzero multiple of alignment of TYPE, suitable for FLEXSIZEOF below.
++   On older platforms without _Alignof, use a pessimistic bound that is
++   safe in practice even if FLEXIBLE_ARRAY_MEMBER is 1.
++   On newer platforms, use _Alignof to get a tighter bound.  */
++
++#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112
++# define FLEXALIGNOF(type) (sizeof (type) & ~ (sizeof (type) - 1))
++#else
++# define FLEXALIGNOF(type) _Alignof (type)
++#endif
++
++/* Upper bound on the size of a struct of type TYPE with a flexible
++   array member named MEMBER that is followed by N bytes of other data.
++   This is not simply sizeof (TYPE) + N, since it may require
++   alignment on unusually picky C11 platforms, and
++   FLEXIBLE_ARRAY_MEMBER may be 1 on pre-C11 platforms.
++   Yield a value less than N if and only if arithmetic overflow occurs.  */
++
++#define FLEXSIZEOF(type, member, n) \
++   ((offsetof (type, member) + FLEXALIGNOF (type) - 1 + (n)) \
++    & ~ (FLEXALIGNOF (type) - 1))
+diff --git a/posix/glob.c b/posix/glob.c
+index c653809118..b2273ea7bc 100644
+--- a/posix/glob.c
++++ b/posix/glob.c
+@@ -15,7 +15,7 @@
+    License along with the GNU C Library; if not, see
+    <http://www.gnu.org/licenses/>.  */
+ 
+-#ifdef        HAVE_CONFIG_H
++#ifndef _LIBC
+ # include <config.h>
+ #endif
+ 
+@@ -27,29 +27,15 @@
+ #include <stdbool.h>
+ #include <stddef.h>
+ #include <stdint.h>
+-
+-/* Outcomment the following line for production quality code.  */
+-/* #define NDEBUG 1 */
+ #include <assert.h>
++#include <unistd.h>
+ 
+-#include <stdio.h>            /* Needed on stupid SunOS for assert.  */
+-
+-#if !defined _LIBC || !defined GLOB_ONLY_P
+-#if defined HAVE_UNISTD_H || defined _LIBC
+-# include <unistd.h>
+-# ifndef POSIX
+-#  ifdef _POSIX_VERSION
+-#   define POSIX
+-#  endif
+-# endif
++#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
++# define WINDOWS32
+ #endif
+ 
+-#include <pwd.h>
+-
+-#if defined HAVE_STDINT_H || defined _LIBC
+-# include <stdint.h>
+-#elif !defined UINTPTR_MAX
+-# define UINTPTR_MAX (~((size_t) 0))
++#ifndef WINDOWS32
++# include <pwd.h>
+ #endif
+ 
+ #include <errno.h>
+@@ -57,24 +43,7 @@
+ # define __set_errno(val) errno = (val)
+ #endif
+ 
+-#if defined HAVE_DIRENT_H || defined __GNU_LIBRARY__
+-# include <dirent.h>
+-#else
+-# define dirent direct
+-# ifdef HAVE_SYS_NDIR_H
+-#  include <sys/ndir.h>
+-# endif
+-# ifdef HAVE_SYS_DIR_H
+-#  include <sys/dir.h>
+-# endif
+-# ifdef HAVE_NDIR_H
+-#  include <ndir.h>
+-# endif
+-# ifdef HAVE_VMSDIR_H
+-#  include "vmsdir.h"
+-# endif /* HAVE_VMSDIR_H */
+-#endif
+-
++#include <dirent.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <alloca.h>
+@@ -87,27 +56,29 @@
+ # define opendir(name) __opendir (name)
+ # define readdir(str) __readdir64 (str)
+ # define getpwnam_r(name, bufp, buf, len, res) \
+-   __getpwnam_r (name, bufp, buf, len, res)
++    __getpwnam_r (name, bufp, buf, len, res)
+ # ifndef __stat64
+ #  define __stat64(fname, buf) __xstat64 (_STAT_VER, fname, buf)
+ # endif
+ # define struct_stat64                struct stat64
++# define FLEXIBLE_ARRAY_MEMBER
+ #else /* !_LIBC */
+-# include "getlogin_r.h"
+-# include "mempcpy.h"
+-# include "stat-macros.h"
+-# include "strdup.h"
+-# define __stat64(fname, buf) stat (fname, buf)
+-# define struct_stat64                struct stat
+-# define __stat(fname, buf)   stat (fname, buf)
+-# define __alloca             alloca
+-# define __readdir            readdir
+-# define __readdir64          readdir64
+-# define __glob_pattern_p     glob_pattern_p
++# define __getlogin_r(buf, len) getlogin_r (buf, len)
++# define __stat64(fname, buf)   stat (fname, buf)
++# define __fxstatat64(_, d, f, st, flag) fstatat (d, f, st, flag)
++# define struct_stat64          struct stat
++# ifndef __MVS__
++#  define __alloca              alloca
++# endif
++# define __readdir              readdir
++# define COMPILE_GLOB64
+ #endif /* _LIBC */
+ 
+ #include <fnmatch.h>
+ 
++#include <flexmember.h>
++#include <glob_internal.h>
++
+ #ifdef _SC_GETPW_R_SIZE_MAX
+ # define GETPW_R_SIZE_MAX()   sysconf (_SC_GETPW_R_SIZE_MAX)
+ #else
+@@ -121,61 +92,59 @@
+ 
+ static const char *next_brace_sub (const char *begin, int flags) __THROWNL;
+ 
++typedef uint_fast8_t dirent_type;
++
++#if !defined _LIBC && !defined HAVE_STRUCT_DIRENT_D_TYPE
++/* Any distinct values will do here.
++   Undef any existing macros out of the way.  */
++# undef DT_UNKNOWN
++# undef DT_DIR
++# undef DT_LNK
++# define DT_UNKNOWN 0
++# define DT_DIR 1
++# define DT_LNK 2
++#endif
++
+ /* 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
++#if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE
++  dirent_type type;
++#endif
++#if defined _LIBC || defined D_INO_IN_DIRENT
+   bool skip_entry;
++#endif
+ };
+ 
+-# 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)
++/* Initialize and return type member of struct readdir_result.  */
++static dirent_type
++readdir_result_type (struct readdir_result d)
+ {
+-  return true;
++#if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE
++# define D_TYPE_TO_RESULT(source) (source)->d_type,
++  return d.type;
++#else
++# define D_TYPE_TO_RESULT(source)
++  return DT_UNKNOWN;
++#endif
+ }
+ 
++/* Initialize and return skip_entry member of struct readdir_result.  */
+ static bool
+-readdir_result_might_be_dir (struct readdir_result d)
++readdir_result_skip_entry (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
++#if defined _LIBC || defined D_INO_IN_DIRENT
++# define D_INO_TO_RESULT(source) (source)->d_ino == 0,
++  return d.skip_entry;
++#else
++# define D_INO_TO_RESULT(source)
++  return false;
++#endif
++}
+ 
+ /* Construct an initializer for a struct readdir_result object from a
+    struct dirent *.  No copy of the name is made.  */
+@@ -186,8 +155,6 @@ readdir_result_might_be_dir (struct readdir_result d)
+     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
+@@ -225,18 +192,55 @@ convert_dirent64 (const struct dirent64 *source)
+ }
+ #endif
+ 
++#ifndef _LIBC
++/* The results of opendir() in this file are not used with dirfd and fchdir,
++   and we do not leak fds to any single-threaded code that could use stdio,
++   therefore save some unnecessary recursion in fchdir.c and opendir_safer.c.
++   FIXME - if the kernel ever adds support for multi-thread safety for
++   avoiding standard fds, then we should use opendir_safer.  */
++# ifdef GNULIB_defined_opendir
++#  undef opendir
++# endif
++# ifdef GNULIB_defined_closedir
++#  undef closedir
++# endif
+ 
+-#ifndef attribute_hidden
+-# define attribute_hidden
++/* Just use malloc.  */
++# define __libc_use_alloca(n) false
++# define alloca_account(len, avar) ((void) (len), (void) (avar), (void *) 0)
++# define extend_alloca_account(buf, len, newlen, avar) \
++    ((void) (buf), (void) (len), (void) (newlen), (void) (avar), (void *) 0)
+ #endif
+ 
++/* Set *R = A + B.  Return true if the answer is mathematically
++   incorrect due to overflow; in this case, *R is the low order
++   bits of the correct answer.  */
++
++static bool
++size_add_wrapv (size_t a, size_t b, size_t *r)
++{
++#if 5 <= __GNUC__ && !defined __ICC
++  return __builtin_add_overflow (a, b, r);
++#else
++  *r = a + b;
++  return *r < a;
++#endif
++}
++
++static bool
++glob_use_alloca (size_t alloca_used, size_t len)
++{
++  size_t size;
++  return (!size_add_wrapv (alloca_used, len, &size)
++          && __libc_use_alloca (size));
++}
++
+ static int glob_in_dir (const char *pattern, const char *directory,
+                       int flags, int (*errfunc) (const char *, int),
+                       glob_t *pglob, size_t alloca_used);
+ extern int __glob_pattern_type (const char *pattern, int quote)
+     attribute_hidden;
+ 
+-#if !defined _LIBC || !defined GLOB_ONLY_P
+ static int prefix_array (const char *prefix, char **array, size_t n) 
__THROWNL;
+ static int collated_compare (const void *, const void *) __THROWNL;
+ 
+@@ -265,16 +269,15 @@ next_brace_sub (const char *cp, int flags)
+   return *cp != '\0' ? cp : NULL;
+ }
+ 
+-#endif /* !defined _LIBC || !defined GLOB_ONLY_P */
+ 
+ /* Do glob searching for PATTERN, placing results in PGLOB.
+    The bits defined above may be set in FLAGS.
+    If a directory cannot be opened or read and ERRFUNC is not nil,
+    it is called with the pathname that caused the error, and the
+-   `errno' value from the failing call; if it returns non-zero
+-   `glob' returns GLOB_ABORTED; if it returns zero, the error is ignored.
++   'errno' value from the failing call; if it returns non-zero
++   'glob' returns GLOB_ABORTED; if it returns zero, the error is ignored.
+    If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned.
+-   Otherwise, `glob' returns zero.  */
++   Otherwise, 'glob' returns zero.  */
+ int
+ #ifdef GLOB_ATTRIBUTE
+ GLOB_ATTRIBUTE
+@@ -292,9 +295,7 @@ glob (const char *pattern, int flags, int (*errfunc) 
(const char *, int),
+   int malloc_dirname = 0;
+   glob_t dirs;
+   int retval = 0;
+-#ifdef _LIBC
+   size_t alloca_used = 0;
+-#endif
+ 
+   if (pattern == NULL || pglob == NULL || (flags & ~__GLOB_FLAGS) != 0)
+     {
+@@ -308,7 +309,7 @@ glob (const char *pattern, int flags, int (*errfunc) 
(const char *, int),
+     flags |= GLOB_ONLYDIR;
+ 
+   if (!(flags & GLOB_DOOFFS))
+-    /* Have to do this so `globfree' knows where to start freeing.  It
++    /* Have to do this so 'globfree' knows where to start freeing.  It
+        also makes all the code that uses gl_offs simpler. */
+     pglob->gl_offs = 0;
+ 
+@@ -372,14 +373,12 @@ glob (const char *pattern, int flags, int (*errfunc) 
(const char *, int),
+         size_t rest_len;
+         char *onealt;
+         size_t pattern_len = strlen (pattern) - 1;
+-#ifdef _LIBC
+-        int alloca_onealt = __libc_use_alloca (alloca_used + pattern_len);
++        int alloca_onealt = glob_use_alloca (alloca_used, pattern_len);
+         if (alloca_onealt)
+           onealt = alloca_account (pattern_len, alloca_used);
+         else
+-#endif
+           {
+-            onealt = (char *) malloc (pattern_len);
++            onealt = malloc (pattern_len);
+             if (onealt == NULL)
+               return GLOB_NOSPACE;
+           }
+@@ -392,11 +391,9 @@ glob (const char *pattern, int flags, int (*errfunc) 
(const char *, int),
+         next = next_brace_sub (begin + 1, flags);
+         if (next == NULL)
+           {
+-            /* It is an illegal expression.  */
++            /* It is an invalid expression.  */
+           illegal_brace:
+-#ifdef _LIBC
+             if (__glibc_unlikely (!alloca_onealt))
+-#endif
+               free (onealt);
+             flags &= ~GLOB_BRACE;
+             goto no_brace;
+@@ -437,9 +434,7 @@ glob (const char *pattern, int flags, int (*errfunc) 
(const char *, int),
+             /* If we got an error, return it.  */
+             if (result && result != GLOB_NOMATCH)
+               {
+-#ifdef _LIBC
+                 if (__glibc_unlikely (!alloca_onealt))
+-#endif
+                   free (onealt);
+                 if (!(flags & GLOB_APPEND))
+                   {
+@@ -458,9 +453,7 @@ glob (const char *pattern, int flags, int (*errfunc) 
(const char *, int),
+             assert (next != NULL);
+           }
+ 
+-#ifdef _LIBC
+         if (__glibc_unlikely (!alloca_onealt))
+-#endif
+           free (onealt);
+ 
+         if (pglob->gl_pathc != firstc)
+@@ -476,14 +469,16 @@ glob (const char *pattern, int flags, int (*errfunc) 
(const char *, int),
+ 
+   /* Find the filename.  */
+   filename = strrchr (pattern, '/');
++
+ #if defined __MSDOS__ || defined WINDOWS32
+-  /* The case of "d:pattern".  Since `:' is not allowed in
++  /* The case of "d:pattern".  Since ':' is not allowed in
+      file names, we can safely assume that wherever it
+      happens in pattern, it signals the filename part.  This
+      is so we could some day support patterns like "[a-z]:foo".  */
+   if (filename == NULL)
+     filename = strchr (pattern, ':');
+ #endif /* __MSDOS__ || WINDOWS32 */
++
+   dirname_modified = 0;
+   if (filename == NULL)
+     {
+@@ -508,11 +503,7 @@ glob (const char *pattern, int flags, int (*errfunc) 
(const char *, int),
+           }
+ 
+         filename = pattern;
+-#ifdef _AMIGA
+-        dirname = (char *) "";
+-#else
+         dirname = (char *) ".";
+-#endif
+         dirlen = 0;
+       }
+     }
+@@ -536,22 +527,21 @@ glob (const char *pattern, int flags, int (*errfunc) 
(const char *, int),
+         char *drive_spec;
+ 
+         ++dirlen;
+-        drive_spec = (char *) __alloca (dirlen + 1);
++        drive_spec = __alloca (dirlen + 1);
+         *((char *) mempcpy (drive_spec, pattern, dirlen)) = '\0';
+         /* For now, disallow wildcards in the drive spec, to
+            prevent infinite recursion in glob.  */
+         if (__glob_pattern_p (drive_spec, !(flags & GLOB_NOESCAPE)))
+           return GLOB_NOMATCH;
+-        /* If this is "d:pattern", we need to copy `:' to DIRNAME
++        /* If this is "d:pattern", we need to copy ':' to DIRNAME
+            as well.  If it's "d:/pattern", don't remove the slash
+            from "d:/", since "d:" and "d:/" are not the same.*/
+       }
+ #endif
+-#ifdef _LIBC
+-      if (__libc_use_alloca (alloca_used + dirlen + 1))
++
++      if (glob_use_alloca (alloca_used, dirlen + 1))
+       newp = alloca_account (dirlen + 1, alloca_used);
+       else
+-#endif
+       {
+         newp = malloc (dirlen + 1);
+         if (newp == NULL)
+@@ -562,14 +552,17 @@ glob (const char *pattern, int flags, int (*errfunc) 
(const char *, int),
+       dirname = newp;
+       ++filename;
+ 
+-      if (filename[0] == '\0'
+ #if defined __MSDOS__ || defined WINDOWS32
+-        && dirname[dirlen - 1] != ':'
+-        && (dirlen < 3 || dirname[dirlen - 2] != ':'
+-            || dirname[dirlen - 1] != '/')
++      bool drive_root = (dirlen > 1
++                         && (dirname[dirlen - 1] == ':'
++                             || (dirlen > 2 && dirname[dirlen - 2] == ':'
++                                 && dirname[dirlen - 1] == '/')));
++#else
++      bool drive_root = false;
+ #endif
+-        && dirlen > 1)
+-      /* "pattern/".  Expand "pattern", appending slashes.  */
++
++      if (filename[0] == '\0' && dirlen > 1 && !drive_root)
++        /* "pattern/".  Expand "pattern", appending slashes.  */
+       {
+         int orig_flags = flags;
+         if (!(flags & GLOB_NOESCAPE) && dirname[dirlen - 1] == '\\')
+@@ -602,7 +595,6 @@ glob (const char *pattern, int flags, int (*errfunc) 
(const char *, int),
+       }
+     }
+ 
+-#ifndef VMS
+   if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && dirname[0] == '~')
+     {
+       if (dirname[1] == '\0' || dirname[1] == '/'
+@@ -612,100 +604,127 @@ glob (const char *pattern, int flags, int (*errfunc) 
(const char *, int),
+         /* Look up home directory.  */
+         char *home_dir = getenv ("HOME");
+         int malloc_home_dir = 0;
+-# ifdef _AMIGA
+-        if (home_dir == NULL || home_dir[0] == '\0')
+-          home_dir = "SYS:";
+-# else
+-#  ifdef WINDOWS32
+-        if (home_dir == NULL || home_dir[0] == '\0')
+-          home_dir = "c:/users/default"; /* poor default */
+-#  else
+         if (home_dir == NULL || home_dir[0] == '\0')
+           {
++#ifdef WINDOWS32
++            /* Windows NT defines HOMEDRIVE and HOMEPATH.  But give
++               preference to HOME, because the user can change HOME.  */
++            const char *home_drive = getenv ("HOMEDRIVE");
++            const char *home_path = getenv ("HOMEPATH");
++
++            if (home_drive != NULL && home_path != NULL)
++              {
++                size_t home_drive_len = strlen (home_drive);
++                size_t home_path_len = strlen (home_path);
++                char *mem = alloca (home_drive_len + home_path_len + 1);
++
++                memcpy (mem, home_drive, home_drive_len);
++                memcpy (mem + home_drive_len, home_path, home_path_len + 1);
++                home_dir = mem;
++              }
++            else
++              home_dir = "c:/users/default"; /* poor default */
++#else
+             int success;
+             char *name;
++            int malloc_name = 0;
+             size_t buflen = GET_LOGIN_NAME_MAX () + 1;
+ 
+             if (buflen == 0)
+-              /* `sysconf' does not support _SC_LOGIN_NAME_MAX.  Try
++              /* 'sysconf' does not support _SC_LOGIN_NAME_MAX.  Try
+                  a moderate value.  */
+               buflen = 20;
+-            name = alloca_account (buflen, alloca_used);
++            if (glob_use_alloca (alloca_used, buflen))
++              name = alloca_account (buflen, alloca_used);
++            else
++              {
++                name = malloc (buflen);
++                if (name == NULL)
++                  {
++                    retval = GLOB_NOSPACE;
++                    goto out;
++                  }
++                malloc_name = 1;
++              }
+ 
+             success = __getlogin_r (name, buflen) == 0;
+             if (success)
+               {
+                 struct passwd *p;
+-#   if defined HAVE_GETPWNAM_R || defined _LIBC
+-                long int pwbuflen = GETPW_R_SIZE_MAX ();
++                char *malloc_pwtmpbuf = NULL;
+                 char *pwtmpbuf;
++# if defined HAVE_GETPWNAM_R || defined _LIBC
++                long int pwbuflenmax = GETPW_R_SIZE_MAX ();
++                size_t pwbuflen = pwbuflenmax;
+                 struct passwd pwbuf;
+-                int malloc_pwtmpbuf = 0;
+                 int save = errno;
+ 
+-#    ifndef _LIBC
+-                if (pwbuflen == -1)
+-                  /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX.
++#  ifndef _LIBC
++                if (! (0 < pwbuflenmax && pwbuflenmax <= SIZE_MAX))
++                  /* 'sysconf' does not support _SC_GETPW_R_SIZE_MAX.
+                      Try a moderate value.  */
+                   pwbuflen = 1024;
+-#    endif
+-                if (__libc_use_alloca (alloca_used + pwbuflen))
++#  endif
++                if (glob_use_alloca (alloca_used, pwbuflen))
+                   pwtmpbuf = alloca_account (pwbuflen, alloca_used);
+                 else
+                   {
+                     pwtmpbuf = malloc (pwbuflen);
+                     if (pwtmpbuf == NULL)
+                       {
++                        if (__glibc_unlikely (malloc_name))
++                          free (name);
+                         retval = GLOB_NOSPACE;
+                         goto out;
+                       }
+-                    malloc_pwtmpbuf = 1;
++                    malloc_pwtmpbuf = pwtmpbuf;
+                   }
+ 
+                 while (getpwnam_r (name, &pwbuf, pwtmpbuf, pwbuflen, &p)
+                        != 0)
+                   {
++                    size_t newlen;
++                    bool v;
+                     if (errno != ERANGE)
+                       {
+                         p = NULL;
+                         break;
+                       }
+-
+-                    if (!malloc_pwtmpbuf
+-                        && __libc_use_alloca (alloca_used
+-                                              + 2 * pwbuflen))
++                    v = size_add_wrapv (pwbuflen, pwbuflen, &newlen);
++                    if (!v && malloc_pwtmpbuf == NULL
++                        && glob_use_alloca (alloca_used, newlen))
+                       pwtmpbuf = extend_alloca_account (pwtmpbuf, pwbuflen,
+-                                                        2 * pwbuflen,
+-                                                        alloca_used);
++                                                        newlen, alloca_used);
+                     else
+                       {
+-                        char *newp = realloc (malloc_pwtmpbuf
+-                                              ? pwtmpbuf : NULL,
+-                                              2 * pwbuflen);
++                        char *newp = (v ? NULL
++                                      : realloc (malloc_pwtmpbuf, newlen));
+                         if (newp == NULL)
+                           {
+-                            if (__glibc_unlikely (malloc_pwtmpbuf))
+-                              free (pwtmpbuf);
++                            free (malloc_pwtmpbuf);
++                            if (__glibc_unlikely (malloc_name))
++                              free (name);
+                             retval = GLOB_NOSPACE;
+                             goto out;
+                           }
+-                        pwtmpbuf = newp;
+-                        pwbuflen = 2 * pwbuflen;
+-                        malloc_pwtmpbuf = 1;
++                        malloc_pwtmpbuf = pwtmpbuf = newp;
+                       }
++                    pwbuflen = newlen;
+                     __set_errno (save);
+                   }
+-#   else
++# else
+                 p = getpwnam (name);
+-#   endif
++# endif
++                if (__glibc_unlikely (malloc_name))
++                  free (name);
+                 if (p != NULL)
+                   {
+-                    if (!malloc_pwtmpbuf)
++                    if (malloc_pwtmpbuf == NULL)
+                       home_dir = p->pw_dir;
+                     else
+                       {
+                         size_t home_dir_len = strlen (p->pw_dir) + 1;
+-                        if (__libc_use_alloca (alloca_used + home_dir_len))
++                        if (glob_use_alloca (alloca_used, home_dir_len))
+                           home_dir = alloca_account (home_dir_len,
+                                                      alloca_used);
+                         else
+@@ -720,26 +739,32 @@ glob (const char *pattern, int flags, int (*errfunc) 
(const char *, int),
+                             malloc_home_dir = 1;
+                           }
+                         memcpy (home_dir, p->pw_dir, home_dir_len);
+-
+-                        free (pwtmpbuf);
+                       }
+                   }
++                free (malloc_pwtmpbuf);
+               }
++            else
++              {
++                if (__glibc_unlikely (malloc_name))
++                  free (name);
++              }
++#endif /* WINDOWS32 */
+           }
+         if (home_dir == NULL || home_dir[0] == '\0')
+           {
++            if (__glibc_unlikely (malloc_home_dir))
++              free (home_dir);
+             if (flags & GLOB_TILDE_CHECK)
+               {
+-                if (__glibc_unlikely (malloc_home_dir))
+-                  free (home_dir);
+                 retval = GLOB_NOMATCH;
+                 goto out;
+               }
+             else
+-              home_dir = (char *) "~"; /* No luck.  */
++              {
++                home_dir = (char *) "~"; /* No luck.  */
++                malloc_home_dir = 0;
++              }
+           }
+-#  endif /* WINDOWS32 */
+-# endif
+         /* Now construct the full directory.  */
+         if (dirname[1] == '\0')
+           {
+@@ -754,8 +779,7 @@ glob (const char *pattern, int flags, int (*errfunc) 
(const char *, int),
+           {
+             char *newp;
+             size_t home_len = strlen (home_dir);
+-            int use_alloca = __libc_use_alloca (alloca_used
+-                                                + home_len + dirlen);
++            int use_alloca = glob_use_alloca (alloca_used, home_len + dirlen);
+             if (use_alloca)
+               newp = alloca_account (home_len + dirlen, alloca_used);
+             else
+@@ -779,12 +803,15 @@ glob (const char *pattern, int flags, int (*errfunc) 
(const char *, int),
+             dirname = newp;
+             dirlen += home_len - 1;
+             malloc_dirname = !use_alloca;
++
++            if (__glibc_unlikely (malloc_home_dir))
++              free (home_dir);
+           }
+         dirname_modified = 1;
+       }
+-# if !defined _AMIGA && !defined WINDOWS32
+       else
+       {
++#ifndef WINDOWS32
+         char *end_name = strchr (dirname, '/');
+         char *user_name;
+         int malloc_user_name = 0;
+@@ -806,7 +833,7 @@ glob (const char *pattern, int flags, int (*errfunc) 
(const char *, int),
+         else
+           {
+             char *newp;
+-            if (__libc_use_alloca (alloca_used + (end_name - dirname)))
++            if (glob_use_alloca (alloca_used, end_name - dirname))
+               newp = alloca_account (end_name - dirname, alloca_used);
+             else
+               {
+@@ -823,11 +850,11 @@ glob (const char *pattern, int flags, int (*errfunc) 
(const char *, int),
+                 char *p = mempcpy (newp, dirname + 1,
+                                    unescape - dirname - 1);
+                 char *q = unescape;
+-                while (*q != '\0')
++                while (q != end_name)
+                   {
+                     if (*q == '\\')
+                       {
+-                        if (q[1] == '\0')
++                        if (q + 1 == end_name)
+                           {
+                             /* "~fo\\o\\" unescape to user_name "foo\\",
+                                but "~fo\\o\\/" unescape to user_name
+@@ -843,7 +870,7 @@ glob (const char *pattern, int flags, int (*errfunc) 
(const char *, int),
+                 *p = '\0';
+               }
+             else
+-              *((char *) mempcpy (newp, dirname + 1, end_name - dirname))
++              *((char *) mempcpy (newp, dirname + 1, end_name - dirname - 1))
+                 = '\0';
+             user_name = newp;
+           }
+@@ -851,20 +878,21 @@ glob (const char *pattern, int flags, int (*errfunc) 
(const char *, int),
+         /* Look up specific user's home directory.  */
+         {
+           struct passwd *p;
++          char *malloc_pwtmpbuf = NULL;
+ #  if defined HAVE_GETPWNAM_R || defined _LIBC
+-          long int buflen = GETPW_R_SIZE_MAX ();
++          long int buflenmax = GETPW_R_SIZE_MAX ();
++          size_t buflen = buflenmax;
+           char *pwtmpbuf;
+-          int malloc_pwtmpbuf = 0;
+           struct passwd pwbuf;
+           int save = errno;
+ 
+ #   ifndef _LIBC
+-          if (buflen == -1)
+-            /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX.  Try a
++          if (! (0 <= buflenmax && buflenmax <= SIZE_MAX))
++            /* Perhaps 'sysconf' does not support _SC_GETPW_R_SIZE_MAX.  Try a
+                moderate value.  */
+             buflen = 1024;
+ #   endif
+-          if (__libc_use_alloca (alloca_used + buflen))
++          if (glob_use_alloca (alloca_used, buflen))
+             pwtmpbuf = alloca_account (buflen, alloca_used);
+           else
+             {
+@@ -877,32 +905,32 @@ glob (const char *pattern, int flags, int (*errfunc) 
(const char *, int),
+                   retval = GLOB_NOSPACE;
+                   goto out;
+                 }
+-              malloc_pwtmpbuf = 1;
++              malloc_pwtmpbuf = pwtmpbuf;
+             }
+ 
+           while (getpwnam_r (user_name, &pwbuf, pwtmpbuf, buflen, &p) != 0)
+             {
++              size_t newlen;
++              bool v;
+               if (errno != ERANGE)
+                 {
+                   p = NULL;
+                   break;
+                 }
+-              if (!malloc_pwtmpbuf
+-                  && __libc_use_alloca (alloca_used + 2 * buflen))
++              v = size_add_wrapv (buflen, buflen, &newlen);
++              if (!v && malloc_pwtmpbuf == NULL
++                  && glob_use_alloca (alloca_used, newlen))
+                 pwtmpbuf = extend_alloca_account (pwtmpbuf, buflen,
+-                                                  2 * buflen, alloca_used);
++                                                  newlen, alloca_used);
+               else
+                 {
+-                  char *newp = realloc (malloc_pwtmpbuf ? pwtmpbuf : NULL,
+-                                        2 * buflen);
++                  char *newp = v ? NULL : realloc (malloc_pwtmpbuf, newlen);
+                   if (newp == NULL)
+                     {
+-                      if (__glibc_unlikely (malloc_pwtmpbuf))
+-                        free (pwtmpbuf);
++                      free (malloc_pwtmpbuf);
+                       goto nomem_getpw;
+                     }
+-                  pwtmpbuf = newp;
+-                  malloc_pwtmpbuf = 1;
++                  malloc_pwtmpbuf = pwtmpbuf = newp;
+                 }
+               __set_errno (save);
+             }
+@@ -923,7 +951,7 @@ glob (const char *pattern, int flags, int (*errfunc) 
(const char *, int),
+                 free (dirname);
+               malloc_dirname = 0;
+ 
+-              if (__libc_use_alloca (alloca_used + home_len + rest_len + 1))
++              if (glob_use_alloca (alloca_used, home_len + rest_len + 1))
+                 dirname = alloca_account (home_len + rest_len + 1,
+                                           alloca_used);
+               else
+@@ -931,8 +959,7 @@ glob (const char *pattern, int flags, int (*errfunc) 
(const char *, int),
+                   dirname = malloc (home_len + rest_len + 1);
+                   if (dirname == NULL)
+                     {
+-                      if (__glibc_unlikely (malloc_pwtmpbuf))
+-                        free (pwtmpbuf);
++                      free (malloc_pwtmpbuf);
+                       retval = GLOB_NOSPACE;
+                       goto out;
+                     }
+@@ -944,24 +971,24 @@ glob (const char *pattern, int flags, int (*errfunc) 
(const char *, int),
+               dirlen = home_len + rest_len;
+               dirname_modified = 1;
+ 
+-              if (__glibc_unlikely (malloc_pwtmpbuf))
+-                free (pwtmpbuf);
++              free (malloc_pwtmpbuf);
+             }
+           else
+             {
+-              if (__glibc_unlikely (malloc_pwtmpbuf))
+-                free (pwtmpbuf);
++              free (malloc_pwtmpbuf);
+ 
+               if (flags & GLOB_TILDE_CHECK)
+-                /* We have to regard it as an error if we cannot find the
+-                   home directory.  */
+-                return GLOB_NOMATCH;
++                {
++                  /* We have to regard it as an error if we cannot find the
++                     home directory.  */
++                  retval = GLOB_NOMATCH;
++                  goto out;
++                }
+             }
+         }
++#endif /* !WINDOWS32 */
+       }
+-# endif       /* Not Amiga && not WINDOWS32.  */
+     }
+-#endif        /* Not VMS.  */
+ 
+   /* Now test whether we looked for "~" or "~NAME".  In this case we
+      can give the answer now.  */
+@@ -980,19 +1007,18 @@ glob (const char *pattern, int flags, int (*errfunc) 
(const char *, int),
+         size_t newcount = pglob->gl_pathc + pglob->gl_offs;
+         char **new_gl_pathv;
+ 
+-        if (newcount > UINTPTR_MAX - (1 + 1)
+-            || newcount + 1 + 1 > ~((size_t) 0) / sizeof (char *))
++        if (newcount > SIZE_MAX / sizeof (char *) - 2)
+           {
+           nospace:
+             free (pglob->gl_pathv);
+             pglob->gl_pathv = NULL;
+             pglob->gl_pathc = 0;
+-            return GLOB_NOSPACE;
++            retval = GLOB_NOSPACE;
++            goto out;
+           }
+ 
+-        new_gl_pathv
+-          = (char **) realloc (pglob->gl_pathv,
+-                               (newcount + 1 + 1) * sizeof (char *));
++        new_gl_pathv = realloc (pglob->gl_pathv,
++                                (newcount + 2) * sizeof (char *));
+         if (new_gl_pathv == NULL)
+           goto nospace;
+         pglob->gl_pathv = new_gl_pathv;
+@@ -1006,12 +1032,19 @@ glob (const char *pattern, int flags, int (*errfunc) 
(const char *, int),
+             p = mempcpy (pglob->gl_pathv[newcount], dirname, dirlen);
+             p[0] = '/';
+             p[1] = '\0';
++            if (__glibc_unlikely (malloc_dirname))
++              free (dirname);
+           }
+         else
+           {
+-            pglob->gl_pathv[newcount] = strdup (dirname);
+-            if (pglob->gl_pathv[newcount] == NULL)
+-              goto nospace;
++            if (__glibc_unlikely (malloc_dirname))
++              pglob->gl_pathv[newcount] = dirname;
++            else
++              {
++                pglob->gl_pathv[newcount] = strdup (dirname);
++                if (pglob->gl_pathv[newcount] == NULL)
++                  goto nospace;
++              }
+           }
+         pglob->gl_pathv[++newcount] = NULL;
+         ++pglob->gl_pathc;
+@@ -1021,7 +1054,8 @@ glob (const char *pattern, int flags, int (*errfunc) 
(const char *, int),
+       }
+ 
+       /* Not found.  */
+-      return GLOB_NOMATCH;
++      retval = GLOB_NOMATCH;
++      goto out;
+     }
+ 
+   meta = __glob_pattern_type (dirname, !(flags & GLOB_NOESCAPE));
+@@ -1067,7 +1101,10 @@ glob (const char *pattern, int flags, int (*errfunc) 
(const char *, int),
+       if (status != 0)
+       {
+         if ((flags & GLOB_NOCHECK) == 0 || status != GLOB_NOMATCH)
+-          return status;
++          {
++            retval = status;
++            goto out;
++          }
+         goto no_matches;
+       }
+ 
+@@ -1078,19 +1115,6 @@ glob (const char *pattern, int flags, int (*errfunc) 
(const char *, int),
+       {
+         size_t old_pathc;
+ 
+-#ifdef        SHELL
+-        {
+-          /* Make globbing interruptible in the bash shell. */
+-          extern int interrupt_state;
+-
+-          if (interrupt_state)
+-            {
+-              globfree (&dirs);
+-              return GLOB_ABORTED;
+-            }
+-        }
+-#endif /* SHELL.  */
+-
+         old_pathc = pglob->gl_pathc;
+         status = glob_in_dir (filename, dirs.gl_pathv[i],
+                               ((flags | GLOB_APPEND)
+@@ -1105,7 +1129,8 @@ glob (const char *pattern, int flags, int (*errfunc) 
(const char *, int),
+             globfree (&dirs);
+             globfree (pglob);
+             pglob->gl_pathc = 0;
+-            return status;
++            retval = status;
++            goto out;
+           }
+ 
+         /* Stick the directory on the front of each name.  */
+@@ -1116,13 +1141,14 @@ glob (const char *pattern, int flags, int (*errfunc) 
(const char *, int),
+             globfree (&dirs);
+             globfree (pglob);
+             pglob->gl_pathc = 0;
+-            return GLOB_NOSPACE;
++            retval = GLOB_NOSPACE;
++            goto out;
+           }
+       }
+ 
+       flags |= GLOB_MAGCHAR;
+ 
+-      /* We have ignored the GLOB_NOCHECK flag in the `glob_in_dir' calls.
++      /* We have ignored the GLOB_NOCHECK flag in the 'glob_in_dir' calls.
+        But if we have not found any matching entry and the GLOB_NOCHECK
+        flag was set we must return the input pattern itself.  */
+       if (pglob->gl_pathc + pglob->gl_offs == oldcount)
+@@ -1134,28 +1160,28 @@ glob (const char *pattern, int flags, int (*errfunc) 
(const char *, int),
+             size_t newcount = pglob->gl_pathc + pglob->gl_offs;
+             char **new_gl_pathv;
+ 
+-            if (newcount > UINTPTR_MAX - 2
+-                || newcount + 2 > ~((size_t) 0) / sizeof (char *))
++            if (newcount > SIZE_MAX / sizeof (char *) - 2)
+               {
+               nospace2:
+                 globfree (&dirs);
+-                return GLOB_NOSPACE;
++                retval = GLOB_NOSPACE;
++                goto out;
+               }
+ 
+-            new_gl_pathv = (char **) realloc (pglob->gl_pathv,
+-                                              (newcount + 2)
+-                                              * sizeof (char *));
++            new_gl_pathv = realloc (pglob->gl_pathv,
++                                    (newcount + 2) * sizeof (char *));
+             if (new_gl_pathv == NULL)
+               goto nospace2;
+             pglob->gl_pathv = new_gl_pathv;
+ 
+-            pglob->gl_pathv[newcount] = __strdup (pattern);
++            pglob->gl_pathv[newcount] = strdup (pattern);
+             if (pglob->gl_pathv[newcount] == NULL)
+               {
+                 globfree (&dirs);
+                 globfree (pglob);
+                 pglob->gl_pathc = 0;
+-                return GLOB_NOSPACE;
++                retval = GLOB_NOSPACE;
++                goto out;
+               }
+ 
+             ++pglob->gl_pathc;
+@@ -1167,7 +1193,8 @@ glob (const char *pattern, int flags, int (*errfunc) 
(const char *, int),
+         else
+           {
+             globfree (&dirs);
+-            return GLOB_NOMATCH;
++            retval = GLOB_NOMATCH;
++            goto out;
+           }
+       }
+ 
+@@ -1213,7 +1240,8 @@ glob (const char *pattern, int flags, int (*errfunc) 
(const char *, int),
+             flags = orig_flags;
+             goto no_matches;
+           }
+-        return status;
++        retval = status;
++        goto out;
+       }
+ 
+       if (dirlen > 0)
+@@ -1225,7 +1253,8 @@ glob (const char *pattern, int flags, int (*errfunc) 
(const char *, int),
+           {
+             globfree (pglob);
+             pglob->gl_pathc = 0;
+-            return GLOB_NOSPACE;
++            retval = GLOB_NOSPACE;
++            goto out;
+           }
+       }
+     }
+@@ -1250,7 +1279,8 @@ glob (const char *pattern, int flags, int (*errfunc) 
(const char *, int),
+             {
+               globfree (pglob);
+               pglob->gl_pathc = 0;
+-              return GLOB_NOSPACE;
++              retval = GLOB_NOSPACE;
++              goto out;
+             }
+           strcpy (&new[len - 2], "/");
+           pglob->gl_pathv[i] = new;
+@@ -1276,32 +1306,12 @@ libc_hidden_def (glob)
+ #endif
+ 
+ 
+-#if !defined _LIBC || !defined GLOB_ONLY_P
+-
+-/* Free storage allocated in PGLOB by a previous `glob' call.  */
+-void
+-globfree (glob_t *pglob)
+-{
+-  if (pglob->gl_pathv != NULL)
+-    {
+-      size_t i;
+-      for (i = 0; i < pglob->gl_pathc; ++i)
+-      free (pglob->gl_pathv[pglob->gl_offs + i]);
+-      free (pglob->gl_pathv);
+-      pglob->gl_pathv = NULL;
+-    }
+-}
+-#if defined _LIBC && !defined globfree
+-libc_hidden_def (globfree)
+-#endif
+-
+-
+ /* Do a collated comparison of A and B.  */
+ static int
+ collated_compare (const void *a, const void *b)
+ {
+-  const char *const s1 = *(const char *const * const) a;
+-  const char *const s2 = *(const char *const * const) b;
++  char *const *ps1 = a; char *s1 = *ps1;
++  char *const *ps2 = b; char *s2 = *ps2;
+ 
+   if (s1 == s2)
+     return 0;
+@@ -1322,28 +1332,24 @@ prefix_array (const char *dirname, char **array, 
size_t n)
+ {
+   size_t i;
+   size_t dirlen = strlen (dirname);
+-#if defined __MSDOS__ || defined WINDOWS32
+-  int sep_char = '/';
+-# define DIRSEP_CHAR sep_char
+-#else
+-# define DIRSEP_CHAR '/'
+-#endif
++  char dirsep_char = '/';
+ 
+   if (dirlen == 1 && dirname[0] == '/')
+     /* DIRNAME is just "/", so normal prepending would get us "//foo".
+        We want "/foo" instead, so don't prepend any chars from DIRNAME.  */
+     dirlen = 0;
++
+ #if defined __MSDOS__ || defined WINDOWS32
+-  else if (dirlen > 1)
++  if (dirlen > 1)
+     {
+       if (dirname[dirlen - 1] == '/' && dirname[dirlen - 2] == ':')
+       /* DIRNAME is "d:/".  Don't prepend the slash from DIRNAME.  */
+       --dirlen;
+       else if (dirname[dirlen - 1] == ':')
+       {
+-        /* DIRNAME is "d:".  Use `:' instead of `/'.  */
++        /* DIRNAME is "d:".  Use ':' instead of '/'.  */
+         --dirlen;
+-        sep_char = ':';
++        dirsep_char = ':';
+       }
+     }
+ #endif
+@@ -1351,7 +1357,7 @@ prefix_array (const char *dirname, char **array, size_t 
n)
+   for (i = 0; i < n; ++i)
+     {
+       size_t eltlen = strlen (array[i]) + 1;
+-      char *new = (char *) malloc (dirlen + 1 + eltlen);
++      char *new = malloc (dirlen + 1 + eltlen);
+       if (new == NULL)
+       {
+         while (i > 0)
+@@ -1361,7 +1367,7 @@ prefix_array (const char *dirname, char **array, size_t 
n)
+ 
+       {
+       char *endp = mempcpy (new, dirname, dirlen);
+-      *endp++ = DIRSEP_CHAR;
++      *endp++ = dirsep_char;
+       mempcpy (endp, array[i], eltlen);
+       }
+       free (array[i]);
+@@ -1371,103 +1377,57 @@ prefix_array (const char *dirname, char **array, 
size_t n)
+   return 0;
+ }
+ 
+-
+-/* We must not compile this function twice.  */
+-#if !defined _LIBC || !defined NO_GLOB_PATTERN_P
+-int
+-__glob_pattern_type (const char *pattern, int quote)
+-{
+-  const char *p;
+-  int ret = 0;
+-
+-  for (p = pattern; *p != '\0'; ++p)
+-    switch (*p)
+-      {
+-      case '?':
+-      case '*':
+-      return 1;
+-
+-      case '\\':
+-      if (quote)
+-        {
+-          if (p[1] != '\0')
+-            ++p;
+-          ret |= 2;
+-        }
+-      break;
+-
+-      case '[':
+-      ret |= 4;
+-      break;
+-
+-      case ']':
+-      if (ret & 4)
+-        return 1;
+-      break;
+-      }
+-
+-  return ret;
+-}
+-
+-/* Return nonzero if PATTERN contains any metacharacters.
+-   Metacharacters can be quoted with backslashes if QUOTE is nonzero.  */
+-int
+-__glob_pattern_p (const char *pattern, int quote)
+-{
+-  return __glob_pattern_type (pattern, quote) == 1;
+-}
+-# ifdef _LIBC
+-weak_alias (__glob_pattern_p, glob_pattern_p)
+-# endif
+-#endif
+-
+-#endif /* !GLOB_ONLY_P */
+-
+-
+ /* We put this in a separate function mainly to allow the memory
+    allocated with alloca to be recycled.  */
+-#if !defined _LIBC || !defined GLOB_ONLY_P
+ static int
+ __attribute_noinline__
+-link_exists2_p (const char *dir, size_t dirlen, const char *fname,
+-             glob_t *pglob
+-# ifndef _LIBC
+-              , int flags
++link_stat (const char *dir, size_t dirlen, const char *fname,
++         glob_t *pglob
++# if !defined _LIBC && !HAVE_FSTATAT
++         , int flags
+ # endif
+-              )
++         )
+ {
+   size_t fnamelen = strlen (fname);
+-  char *fullname = (char *) __alloca (dirlen + 1 + fnamelen + 1);
++  char *fullname = __alloca (dirlen + 1 + fnamelen + 1);
+   struct stat st;
+-# ifndef _LIBC
+-  struct_stat64 st64;
+-# endif
+ 
+   mempcpy (mempcpy (mempcpy (fullname, dir, dirlen), "/", 1),
+          fname, fnamelen + 1);
+ 
+-# ifdef _LIBC
+-  return (*pglob->gl_stat) (fullname, &st) == 0;
+-# else
+-  return ((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
+-         ? (*pglob->gl_stat) (fullname, &st)
+-         : __stat64 (fullname, &st64)) == 0);
++# if !defined _LIBC && !HAVE_FSTATAT
++  if (__builtin_expect ((flags & GLOB_ALTDIRFUNC) == 0, 1))
++    {
++      struct_stat64 st64;
++      return __stat64 (fullname, &st64);
++    }
+ # endif
++  return (*pglob->gl_stat) (fullname, &st);
+ }
+-# ifdef _LIBC
+-#  define link_exists_p(dfd, dirname, dirnamelen, fname, pglob, flags) \
+-  (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)                            \
+-   ? link_exists2_p (dirname, dirnamelen, fname, pglob)                       
      \
+-   : ({ struct stat64 st64;                                                 \
+-       __fxstatat64 (_STAT_VER, dfd, fname, &st64, 0) == 0; }))
++
++/* Return true if DIR/FNAME exists.  */
++static int
++link_exists_p (int dfd, const char *dir, size_t dirlen, const char *fname,
++             glob_t *pglob, int flags)
++{
++  int status;
++# if defined _LIBC || HAVE_FSTATAT
++  if (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0))
++    status = link_stat (dir, dirlen, fname, pglob);
++  else
++    {
++      /* dfd cannot be -1 here, because dirfd never returns -1 on
++       glibc, or on hosts that have fstatat.  */
++      struct_stat64 st64;
++      status = __fxstatat64 (_STAT_VER, dfd, fname, &st64, 0);
++    }
+ # else
+-#  define link_exists_p(dfd, dirname, dirnamelen, fname, pglob, flags) \
+-  link_exists2_p (dirname, dirnamelen, fname, pglob, flags)
++  status = link_stat (dir, dirlen, fname, pglob, flags);
+ # endif
+-#endif
+-
++  return status == 0 || errno == EOVERFLOW;
++}
+ 
+-/* Like `glob', but PATTERN is a final pathname component,
++/* Like 'glob', but PATTERN is a final pathname component,
+    and matches are searched for in DIRECTORY.
+    The GLOB_NOSORT bit in FLAGS is ignored.  No sorting is ever done.
+    The GLOB_APPEND flag is assumed to be set (always appends).  */
+@@ -1478,25 +1438,25 @@ glob_in_dir (const char *pattern, const char 
*directory, int flags,
+ {
+   size_t dirlen = strlen (directory);
+   void *stream = NULL;
+-  struct globnames
+-    {
+-      struct globnames *next;
+-      size_t count;
+-      char *name[64];
+-    };
+-#define INITIAL_COUNT sizeof (init_names.name) / sizeof (init_names.name[0])
+-  struct globnames init_names;
+-  struct globnames *names = &init_names;
+-  struct globnames *names_alloca = &init_names;
++# define GLOBNAMES_MEMBERS(nnames) \
++    struct globnames *next; size_t count; char *name[nnames];
++  struct globnames { GLOBNAMES_MEMBERS (FLEXIBLE_ARRAY_MEMBER) };
++  struct { GLOBNAMES_MEMBERS (64) } init_names_buf;
++  struct globnames *init_names = (struct globnames *) &init_names_buf;
++  struct globnames *names = init_names;
++  struct globnames *names_alloca = init_names;
+   size_t nfound = 0;
+   size_t cur = 0;
+   int meta;
+   int save;
++  int result;
+ 
+-  alloca_used += sizeof (init_names);
++  alloca_used += sizeof init_names_buf;
+ 
+-  init_names.next = NULL;
+-  init_names.count = INITIAL_COUNT;
++  init_names->next = NULL;
++  init_names->count = ((sizeof init_names_buf
++                        - offsetof (struct globnames, name))
++                       / sizeof init_names->name[0]);
+ 
+   meta = __glob_pattern_type (pattern, !(flags & GLOB_NOESCAPE));
+   if (meta == 0 && (flags & (GLOB_NOCHECK|GLOB_NOMAGIC)))
+@@ -1516,14 +1476,16 @@ glob_in_dir (const char *pattern, const char 
*directory, int flags,
+       struct_stat64 st64;
+       } ust;
+       size_t patlen = strlen (pattern);
+-      int alloca_fullname = __libc_use_alloca (alloca_used
+-                                             + dirlen + 1 + patlen + 1);
++      size_t fullsize;
++      bool alloca_fullname
++        = (! size_add_wrapv (dirlen + 1, patlen + 1, &fullsize)
++           && glob_use_alloca (alloca_used, fullsize));
+       char *fullname;
+       if (alloca_fullname)
+-      fullname = alloca_account (dirlen + 1 + patlen + 1, alloca_used);
++        fullname = alloca_account (fullsize, alloca_used);
+       else
+       {
+-        fullname = malloc (dirlen + 1 + patlen + 1);
++        fullname = malloc (fullsize);
+         if (fullname == NULL)
+           return GLOB_NOSPACE;
+       }
+@@ -1531,9 +1493,11 @@ glob_in_dir (const char *pattern, const char 
*directory, int flags,
+       mempcpy (mempcpy (mempcpy (fullname, directory, dirlen),
+                       "/", 1),
+              pattern, patlen + 1);
+-      if ((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
++      if (((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
+          ? (*pglob->gl_stat) (fullname, &ust.st)
+-         : __stat64 (fullname, &ust.st64)) == 0)
++          : __stat64 (fullname, &ust.st64))
++         == 0)
++        || errno == EOVERFLOW)
+       /* We found this file to be existing.  Now tell the rest
+          of the function to copy this name into the result.  */
+       flags |= GLOB_NOCHECK;
+@@ -1555,16 +1519,10 @@ glob_in_dir (const char *pattern, const char 
*directory, int flags,
+       }
+       else
+       {
+-#ifdef _LIBC
+         int dfd = (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
+                    ? -1 : dirfd ((DIR *) stream));
+-#endif
+         int fnm_flags = ((!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0)
+-                         | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0)
+-#if defined _AMIGA || defined VMS
+-                         | FNM_CASEFOLD
+-#endif
+-                         );
++                         | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0));
+         flags |= GLOB_MAGCHAR;
+ 
+         while (1)
+@@ -1584,19 +1542,24 @@ glob_in_dir (const char *pattern, const char 
*directory, int flags,
+             }
+             if (d.name == NULL)
+               break;
+-            if (d.skip_entry)
++            if (readdir_result_skip_entry (d))
+               continue;
+ 
+             /* If we shall match only directories use the information
+                provided by the dirent call if possible.  */
+-            if ((flags & GLOB_ONLYDIR) && !readdir_result_might_be_dir (d))
+-              continue;
++            if (flags & GLOB_ONLYDIR)
++              switch (readdir_result_type (d))
++                {
++                case DT_DIR: case DT_LNK: case DT_UNKNOWN: break;
++                default: continue;
++                }
+ 
+             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 (!readdir_result_might_be_symlink (d)
++                dirent_type type = readdir_result_type (d);
++                if (! (type == DT_LNK || type == DT_UNKNOWN)
+                     || link_exists_p (dfd, directory, dirlen, d.name,
+                                       pglob, flags))
+                   {
+@@ -1604,10 +1567,13 @@ glob_in_dir (const char *pattern, const char 
*directory, int flags,
+                       {
+                         struct globnames *newnames;
+                         size_t count = names->count * 2;
+-                        size_t size = (sizeof (struct globnames)
+-                                       + ((count - INITIAL_COUNT)
+-                                          * sizeof (char *)));
+-                        if (__libc_use_alloca (alloca_used + size))
++                        size_t nameoff = offsetof (struct globnames, name);
++                        size_t size = FLEXSIZEOF (struct globnames, name,
++                                                  count * sizeof (char *));
++                        if ((SIZE_MAX - nameoff) / 2 / sizeof (char *)
++                            < names->count)
++                          goto memory_error;
++                        if (glob_use_alloca (alloca_used, size))
+                           newnames = names_alloca
+                             = alloca_account (size, alloca_used);
+                         else if ((newnames = malloc (size))
+@@ -1623,6 +1589,8 @@ glob_in_dir (const char *pattern, const char *directory, 
int flags,
+                       goto memory_error;
+                     ++cur;
+                     ++nfound;
++                    if (SIZE_MAX - pglob->gl_offs <= nfound)
++                      goto memory_error;
+                   }
+               }
+           }
+@@ -1633,29 +1601,27 @@ glob_in_dir (const char *pattern, const char 
*directory, int flags,
+     {
+       size_t len = strlen (pattern);
+       nfound = 1;
+-      names->name[cur] = (char *) malloc (len + 1);
++      names->name[cur] = malloc (len + 1);
+       if (names->name[cur] == NULL)
+       goto memory_error;
+       *((char *) mempcpy (names->name[cur++], pattern, len)) = '\0';
+     }
+ 
+-  int result = GLOB_NOMATCH;
++  result = GLOB_NOMATCH;
+   if (nfound != 0)
+     {
++      char **new_gl_pathv;
+       result = 0;
+ 
+-      if (pglob->gl_pathc > UINTPTR_MAX - pglob->gl_offs
+-        || pglob->gl_pathc + pglob->gl_offs > UINTPTR_MAX - nfound
+-        || pglob->gl_pathc + pglob->gl_offs + nfound > UINTPTR_MAX - 1
+-        || (pglob->gl_pathc + pglob->gl_offs + nfound + 1
+-            > UINTPTR_MAX / sizeof (char *)))
++      if (SIZE_MAX / sizeof (char *) - pglob->gl_pathc
++        < pglob->gl_offs + nfound + 1)
+       goto memory_error;
+ 
+-      char **new_gl_pathv;
+       new_gl_pathv
+-      = (char **) realloc (pglob->gl_pathv,
+-                           (pglob->gl_pathc + pglob->gl_offs + nfound + 1)
+-                           * sizeof (char *));
++      = realloc (pglob->gl_pathv,
++                 (pglob->gl_pathc + pglob->gl_offs + nfound + 1)
++                  * sizeof (char *));
++
+       if (new_gl_pathv == NULL)
+       {
+       memory_error:
+@@ -1671,7 +1637,7 @@ glob_in_dir (const char *pattern, const char *directory, 
int flags,
+                and this is the block assigned to OLD here.  */
+             if (names == NULL)
+               {
+-                assert (old == &init_names);
++                assert (old == init_names);
+                 break;
+               }
+             cur = names->count;
+@@ -1697,7 +1663,7 @@ glob_in_dir (const char *pattern, const char *directory, 
int flags,
+                and this is the block assigned to OLD here.  */
+             if (names == NULL)
+               {
+-                assert (old == &init_names);
++                assert (old == init_names);
+                 break;
+               }
+             cur = names->count;
+diff --git a/posix/glob64.c b/posix/glob64.c
+index 6cb3d654a8..a515a1c12f 100644
+--- a/posix/glob64.c
++++ b/posix/glob64.c
+@@ -43,10 +43,4 @@ glob64 (const char *pattern, int flags,
+ }
+ libc_hidden_def (glob64)
+ 
+-void
+-globfree64 (glob64_t *pglob)
+-{
+-}
+-libc_hidden_def (globfree64)
+-
+ stub_warning (glob64)
+diff --git a/posix/glob_internal.h b/posix/glob_internal.h
+new file mode 100644
+index 0000000000..12c93660b7
+--- /dev/null
++++ b/posix/glob_internal.h
+@@ -0,0 +1,57 @@
++/* Shared definition for glob and glob_pattern_p.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#ifndef GLOB_INTERNAL_H
++# define GLOB_INTERNAL_H
++
++static inline int
++__glob_pattern_type (const char *pattern, int quote)
++{
++  const char *p;
++  int ret = 0;
++
++  for (p = pattern; *p != '\0'; ++p)
++    switch (*p)
++      {
++      case '?':
++      case '*':
++        return 1;
++
++      case '\\':
++        if (quote)
++          {
++            if (p[1] != '\0')
++              ++p;
++            ret |= 2;
++          }
++        break;
++
++      case '[':
++        ret |= 4;
++        break;
++
++      case ']':
++        if (ret & 4)
++          return 1;
++        break;
++      }
++
++  return ret;
++}
++
++#endif /* GLOB_INTERNAL_H  */
+diff --git a/posix/glob_pattern_p.c b/posix/glob_pattern_p.c
+new file mode 100644
+index 0000000000..a17d337182
+--- /dev/null
++++ b/posix/glob_pattern_p.c
+@@ -0,0 +1,33 @@
++/* Return nonzero if PATTERN contains any metacharacters.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#ifndef _LIBC
++# include <config.h>
++#endif
++
++#include <glob.h>
++#include "glob_internal.h"
++
++/* Return nonzero if PATTERN contains any metacharacters.
++   Metacharacters can be quoted with backslashes if QUOTE is nonzero.  */
++int
++__glob_pattern_p (const char *pattern, int quote)
++{
++  return __glob_pattern_type (pattern, quote) == 1;
++}
++weak_alias (__glob_pattern_p, glob_pattern_p)
+diff --git a/posix/globfree.c b/posix/globfree.c
+new file mode 100644
+index 0000000000..042e29d9b0
 --- /dev/null
-+++ b/nptl/tst-rwlock20.c
-@@ -0,0 +1,116 @@
-+/* Test program for a read-phase / write-phase explicit hand-over.
++++ b/posix/globfree.c
+@@ -0,0 +1,41 @@
++/* Frees the dynamically allocated storage from an earlier call to glob.
 +   Copyright (C) 2017 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.
++   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
@@ -3090,108 +5010,69 @@ index 0000000000..4aeea2b8f5
 +   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 <errno.h>
-+#include <error.h>
-+#include <pthread.h>
-+#include <stdio.h>
-+#include <stdlib.h>
-+#include <unistd.h>
-+#include <stdint.h>
-+#include <time.h>
-+#include <atomic.h>
-+#include <support/xthread.h>
-+
-+/* We realy want to set threads to 2 to reproduce this issue. The goal
-+   is to have one primary writer and a single reader, and to hit the
-+   bug that happens in the interleaving of those two phase transitions.
-+   However, on most hardware, adding a second writer seems to help the
-+   interleaving happen slightly more often, say 20% of the time.  On a
-+   16 core ppc64 machine this fails 100% of the time with an unpatched
-+   glibc.  On a 8 core x86_64 machine this fails ~93% of the time, but
-+   it doesn't fail at all on a 4 core system, so having available
-+   unloaded cores makes a big difference in reproducibility.  On an 8
-+   core qemu/kvm guest the reproducer reliability drops to ~10%.  */
-+#define THREADS 3
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
 +
-+#define KIND PTHREAD_RWLOCK_PREFER_READER_NP
++#ifndef _LIBC
++# include <config.h>
++#endif
 +
-+static pthread_rwlock_t lock;
-+static int done = 0;
++#include <glob.h>
++#include <stdlib.h>
 +
-+static void*
-+tf (void* arg)
++/* Free storage allocated in PGLOB by a previous `glob' call.  */
++void
++globfree (glob_t *pglob)
 +{
-+  while (atomic_load_relaxed (&done) == 0)
++  if (pglob->gl_pathv != NULL)
 +    {
-+      int rcnt = 0;
-+      int wcnt = 100;
-+      if ((uintptr_t) arg == 0)
-+      {
-+        rcnt = 1;
-+        wcnt = 1;
-+      }
-+
-+      do
-+      {
-+        if (wcnt)
-+          {
-+            xpthread_rwlock_wrlock (&lock);
-+            xpthread_rwlock_unlock (&lock);
-+            wcnt--;
-+        }
-+        if (rcnt)
-+          {
-+            xpthread_rwlock_rdlock (&lock);
-+            xpthread_rwlock_unlock (&lock);
-+            rcnt--;
-+        }
-+      }
-+      while ((atomic_load_relaxed (&done) == 0) && (rcnt + wcnt > 0));
-+
++      size_t i;
++      for (i = 0; i < pglob->gl_pathc; ++i)
++        free (pglob->gl_pathv[pglob->gl_offs + i]);
++      free (pglob->gl_pathv);
++      pglob->gl_pathv = NULL;
 +    }
-+    return NULL;
 +}
++#ifndef globfree
++libc_hidden_def (globfree)
++#endif
+diff --git a/posix/globfree64.c b/posix/globfree64.c
+new file mode 100644
+index 0000000000..c9f8908a4e
+--- /dev/null
++++ b/posix/globfree64.c
+@@ -0,0 +1,31 @@
++/* Frees the dynamically allocated storage from an earlier call to glob.
++   Copyright (C) 2017 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.
 +
-+static int
-+do_test (void)
-+{
-+  pthread_t thr[THREADS];
-+  int n;
-+  pthread_rwlockattr_t attr;
-+
-+  xpthread_rwlockattr_init (&attr);
-+  xpthread_rwlockattr_setkind_np (&attr, KIND);
-+
-+  xpthread_rwlock_init (&lock, &attr);
-+
-+  /* Make standard error the same as standard output.  */
-+  dup2 (1, 2);
-+
-+  /* Make sure we see all message, even those on stdout.  */
-+  setvbuf (stdout, NULL, _IONBF, 0);
-+
-+  for (n = 0; n < THREADS; ++n)
-+    thr[n] = xpthread_create (NULL, tf, (void *) (uintptr_t) n);
++   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/>.  */
 +
-+  struct timespec delay;
-+  delay.tv_sec = 10;
-+  delay.tv_nsec = 0;
-+  nanosleep (&delay, NULL);
-+  atomic_store_relaxed (&done, 1);
++#ifndef _LIBC
++# include <config.h>
++#endif
 +
-+  /* Wait for all the threads.  */
-+  for (n = 0; n < THREADS; ++n)
-+    xpthread_join (thr[n]);
++#include <glob.h>
++#include <stdlib.h>
 +
-+  return 0;
++/* Free storage allocated in PGLOB by a previous `glob' call.  */
++void
++globfree64 (glob64_t *pglob)
++{
 +}
-+
-+#include <support/test-driver.c>
++libc_hidden_def (globfree64)
 diff --git a/posix/globtest.sh b/posix/globtest.sh
 index f9cc80b4b5..73f7ae31cc 100755
 --- a/posix/globtest.sh
@@ -3219,6 +5100,155 @@ index f9cc80b4b5..73f7ae31cc 100755
      echo "All OK." > $logfile
  fi
  
+diff --git a/posix/tst-glob-tilde.c b/posix/tst-glob-tilde.c
+new file mode 100644
+index 0000000000..6886f4371f
+--- /dev/null
++++ b/posix/tst-glob-tilde.c
+@@ -0,0 +1,143 @@
++/* Check for GLOB_TIDLE heap allocation issues (bugs 22320, 22325, 22332).
++   Copyright (C) 2017 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 <glob.h>
++#include <mcheck.h>
++#include <nss.h>
++#include <pwd.h>
++#include <stdlib.h>
++#include <string.h>
++#include <support/check.h>
++#include <support/support.h>
++
++/* Flag which indicates whether to pass the GLOB_ONLYDIR flag.  */
++static int do_onlydir;
++
++/* Flag which indicates whether to pass the GLOB_NOCHECK flag.  */
++static int do_nocheck;
++
++/* Flag which indicates whether to pass the GLOB_MARK flag.  */
++static int do_mark;
++
++/* Flag which indicates whether to pass the GLOB_NOESCAPE flag.  */
++static int do_noescape;
++
++static void
++one_test (const char *prefix, const char *middle, const char *suffix)
++{
++  char *pattern = xasprintf ("%s%s%s", prefix, middle, suffix);
++  int flags = GLOB_TILDE;
++  if (do_onlydir)
++    flags |= GLOB_ONLYDIR;
++  if (do_nocheck)
++    flags |= GLOB_NOCHECK;
++  if (do_mark)
++    flags |= GLOB_MARK;
++  if (do_noescape)
++    flags |= GLOB_NOESCAPE;
++  glob_t gl;
++  /* This glob call might result in crashes or memory leaks.  */
++  if (glob (pattern, flags, NULL, &gl) == 0)
++    globfree (&gl);
++  free (pattern);
++}
++
++enum
++  {
++    /* The largest base being tested.  */
++    largest_base_size = 500000,
++
++    /* The actual size is the base size plus a variable whose absolute
++       value is not greater than this.  This helps malloc to trigger
++       overflows.  */
++    max_size_skew = 16,
++
++    /* The maximum string length supported by repeating_string
++       below.  */
++    repeat_size = largest_base_size + max_size_skew,
++  };
++
++/* Used to construct strings which repeat a single character 'x'.  */
++static char *repeat;
++
++/* Return a string of SIZE characters.  */
++const char *
++repeating_string (int size)
++{
++  TEST_VERIFY (size >= 0);
++  TEST_VERIFY (size <= repeat_size);
++  const char *repeated_shifted = repeat + repeat_size - size;
++  TEST_VERIFY (strlen (repeated_shifted) == size);
++  return repeated_shifted;
++}
++
++static int
++do_test (void)
++{
++  /* Avoid network-based NSS modules and initialize nss_files with a
++     dummy lookup.  This has to come before mtrace because NSS does
++     not free all memory.  */
++  __nss_configure_lookup ("passwd", "files");
++  (void) getpwnam ("root");
++
++  mtrace ();
++
++  repeat = xmalloc (repeat_size + 1);
++  memset (repeat, 'x', repeat_size);
++  repeat[repeat_size] = '\0';
++
++  /* These numbers control the size of the user name.  The values
++     cover the minimum (0), a typical size (8), a large
++     stack-allocated size (100000), and a somewhat large
++     heap-allocated size (largest_base_size).  */
++  static const int base_sizes[] = { 0, 8, 100, 100000, largest_base_size, -1 
};
++
++  for (do_onlydir = 0; do_onlydir < 2; ++do_onlydir)
++    for (do_nocheck = 0; do_nocheck < 2; ++do_nocheck)
++      for (do_mark = 0; do_mark < 2; ++do_mark)
++      for (do_noescape = 0; do_noescape < 2; ++do_noescape)
++        for (int base_idx = 0; base_sizes[base_idx] >= 0; ++base_idx)
++          {
++            for (int size_skew = -max_size_skew; size_skew <= max_size_skew;
++                 ++size_skew)
++              {
++                int size = base_sizes[base_idx] + size_skew;
++                if (size < 0)
++                  continue;
++
++                const char *user_name = repeating_string (size);
++                one_test ("~", user_name, "/a/b");
++                one_test ("~", user_name, "x\\x\\x////x\\a");
++              }
++
++            const char *user_name = repeating_string (base_sizes[base_idx]);
++            one_test ("~", user_name, "");
++            one_test ("~", user_name, "/");
++            one_test ("~", user_name, "/a");
++            one_test ("~", user_name, "/*/*");
++            one_test ("~", user_name, "\\/");
++            one_test ("/~", user_name, "");
++            one_test ("*/~", user_name, "/a/b");
++          }
++
++  free (repeat);
++
++  return 0;
++}
++
++#include <support/test-driver.c>
 diff --git a/resolv/Makefile b/resolv/Makefile
 index fdc37edff1..01086d569f 100644
 --- a/resolv/Makefile
@@ -8513,6 +10543,38 @@ index a74083786e..5ea8a4a259 100644
    "LD_LIBRARY_PATH\0"                                                       \
    "LD_ORIGIN_PATH\0"                                                        \
    "LD_PRELOAD\0"                                                            \
+diff --git a/sysdeps/gnu/glob64.c b/sysdeps/gnu/glob64.c
+index d1e4e6f0d5..52e97e2f6a 100644
+--- a/sysdeps/gnu/glob64.c
++++ b/sysdeps/gnu/glob64.c
+@@ -15,11 +15,8 @@
+ #undef __stat
+ #define __stat(file, buf) __xstat64 (_STAT_VER, file, buf)
+ 
+-#define NO_GLOB_PATTERN_P 1
+-
+ #define COMPILE_GLOB64        1
+ 
+ #include <posix/glob.c>
+ 
+ libc_hidden_def (glob64)
+-libc_hidden_def (globfree64)
+diff --git a/sysdeps/gnu/globfree64.c b/sysdeps/gnu/globfree64.c
+new file mode 100644
+index 0000000000..f092d0bf8b
+--- /dev/null
++++ b/sysdeps/gnu/globfree64.c
+@@ -0,0 +1,10 @@
++#include <dirent.h>
++#include <glob.h>
++#include <sys/stat.h>
++
++#define glob_t glob64_t
++#define globfree(pglob) globfree64 (pglob)
++
++#include <posix/globfree.c>
++
++libc_hidden_def (globfree64)
 diff --git a/sysdeps/hppa/__longjmp.c b/sysdeps/hppa/__longjmp.c
 index a7eefc7ad6..2fedb1d738 100644
 --- a/sysdeps/hppa/__longjmp.c
@@ -9075,6 +11137,77 @@ index 99c00f493d..0694ac1362 100644
        value = map->l_addr;
      }
    else
+diff --git a/sysdeps/unix/sysv/linux/Makefile 
b/sysdeps/unix/sysv/linux/Makefile
+index b3d68665f9..beb1c29111 100644
+--- a/sysdeps/unix/sysv/linux/Makefile
++++ b/sysdeps/unix/sysv/linux/Makefile
+@@ -141,7 +141,7 @@ endif
+ ifeq ($(subdir),posix)
+ sysdep_headers += bits/initspin.h
+ 
+-sysdep_routines += sched_getcpu
++sysdep_routines += sched_getcpu oldglob
+ 
+ tests += tst-affinity tst-affinity-pid
+ 
+diff --git a/sysdeps/unix/sysv/linux/alpha/glob.c 
b/sysdeps/unix/sysv/linux/alpha/glob.c
+index 2d7d287a25..1b813c1cfd 100644
+--- a/sysdeps/unix/sysv/linux/alpha/glob.c
++++ b/sysdeps/unix/sysv/linux/alpha/glob.c
+@@ -42,10 +42,6 @@ extern void __new_globfree (glob_t *__pglob);
+ #undef globfree64
+ 
+ versioned_symbol (libc, __new_glob, glob, GLIBC_2_1);
+-versioned_symbol (libc, __new_globfree, globfree, GLIBC_2_1);
+ libc_hidden_ver (__new_glob, glob)
+-libc_hidden_ver (__new_globfree, globfree)
+ 
+ weak_alias (__new_glob, glob64)
+-weak_alias (__new_globfree, globfree64)
+-libc_hidden_ver (__new_globfree, globfree64)
+diff --git a/sysdeps/unix/sysv/linux/alpha/globfree.c 
b/sysdeps/unix/sysv/linux/alpha/globfree.c
+new file mode 100644
+index 0000000000..98cf1c200b
+--- /dev/null
++++ b/sysdeps/unix/sysv/linux/alpha/globfree.c
+@@ -0,0 +1,37 @@
++/* Compat globfree.  Linux/alpha version.
++   Copyright (C) 2017 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/>.  */
++
++#define globfree64 __no_globfree64_decl
++#include <sys/types.h>
++#include <glob.h>
++#include <shlib-compat.h>
++
++#define globfree(pglob) \
++  __new_globfree (pglob)
++
++extern void __new_globfree (glob_t *__pglob);
++
++#include <posix/globfree.c>
++
++#undef globfree64
++
++versioned_symbol (libc, __new_globfree, globfree, GLIBC_2_1);
++libc_hidden_ver (__new_globfree, globfree)
++
++weak_alias (__new_globfree, globfree64)
++libc_hidden_ver (__new_globfree, globfree64)
 diff --git a/sysdeps/unix/sysv/linux/alpha/localplt.data 
b/sysdeps/unix/sysv/linux/alpha/localplt.data
 index cca17f1e34..1f0e3b494e 100644
 --- a/sysdeps/unix/sysv/linux/alpha/localplt.data
@@ -9854,6 +11987,63 @@ index d8dd0431a4..c0cd59e9f5 100644
  
  /* We do nothing with the return, except hand it back to someone else */
  #undef  DO_CALL_NOERRNO
+diff --git a/sysdeps/unix/sysv/linux/i386/glob64.c 
b/sysdeps/unix/sysv/linux/i386/glob64.c
+index f68195137e..230f9fc037 100644
+--- a/sysdeps/unix/sysv/linux/i386/glob64.c
++++ b/sysdeps/unix/sysv/linux/i386/glob64.c
+@@ -19,6 +19,7 @@
+ #include <dirent.h>
+ #include <glob.h>
+ #include <sys/stat.h>
++#include <shlib-compat.h>
+ 
+ #define dirent dirent64
+ #define __readdir(dirp) __readdir64 (dirp)
+@@ -33,44 +34,9 @@
+ #undef __stat
+ #define __stat(file, buf) __xstat64 (_STAT_VER, file, buf)
+ 
+-#define NO_GLOB_PATTERN_P 1
+-
+ #define COMPILE_GLOB64        1
+ 
+ #include <posix/glob.c>
+ 
+-#include "shlib-compat.h"
+-
+-libc_hidden_def (globfree64)
+-
+ versioned_symbol (libc, __glob64, glob64, GLIBC_2_2);
+ libc_hidden_ver (__glob64, glob64)
+-
+-#if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2)
+-
+-#include <sysdeps/unix/sysv/linux/i386/olddirent.h>
+-
+-int __old_glob64 (const char *__pattern, int __flags,
+-                int (*__errfunc) (const char *, int),
+-                glob64_t *__pglob);
+-
+-#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
+-
+-#define GLOB_ONLY_P 1
+-
+-#include <posix/glob.c>
+-
+-compat_symbol (libc, __old_glob64, glob64, GLIBC_2_1);
+-#endif
 diff --git a/sysdeps/unix/sysv/linux/i386/localplt.data 
b/sysdeps/unix/sysv/linux/i386/localplt.data
 index 2c2584956d..8ea4333846 100644
 --- a/sysdeps/unix/sysv/linux/i386/localplt.data
@@ -9867,6 +12057,13 @@ index 2c2584956d..8ea4333846 100644
  # The main malloc is interposed into the dynamic linker, for
  # allocations after the initial link (when dlopen is used).
  ld.so: malloc + REL R_386_GLOB_DAT
+diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/globfree64.c 
b/sysdeps/unix/sysv/linux/mips/mips64/n64/globfree64.c
+new file mode 100644
+index 0000000000..abc35fdd2b
+--- /dev/null
++++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/globfree64.c
+@@ -0,0 +1 @@
++/* glob64 is in globfree64.c */
 diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/posix_fadvise64.c 
b/sysdeps/unix/sysv/linux/mips/mips64/n64/posix_fadvise64.c
 index 9776ee96e5..5a6379613b 100644
 --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/posix_fadvise64.c
@@ -9879,6 +12076,54 @@ index 9776ee96e5..5a6379613b 100644
 +_weak_alias (posix_fadvise, posix_fadvise64);
  #endif
  _strong_alias (__posix_fadvise64_l64, posix_fadvise);
+diff --git a/sysdeps/unix/sysv/linux/oldglob.c 
b/sysdeps/unix/sysv/linux/oldglob.c
+new file mode 100644
+index 0000000000..8233e57ce9
+--- /dev/null
++++ b/sysdeps/unix/sysv/linux/oldglob.c
+@@ -0,0 +1,42 @@
++#include <shlib-compat.h>
++
++#if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2)
++
++#include <dirent.h>
++#include <glob.h>
++#include <sys/stat.h>
++
++#include <sysdeps/unix/sysv/linux/i386/olddirent.h>
++
++int __old_glob64 (const char *__pattern, int __flags,
++                int (*__errfunc) (const char *, int),
++                glob64_t *__pglob);
++libc_hidden_proto (__old_glob64);
++
++#define dirent __old_dirent64
++#define GL_READDIR(pglob, stream) \
++  ((struct __old_dirent64 *) (pglob)->gl_readdir (stream))
++#undef __readdir
++#define __readdir(dirp) __old_readdir64 (dirp)
++
++#define glob_t glob64_t
++#define glob(pattern, flags, errfunc, pglob) \
++  __old_glob64 (pattern, flags, errfunc, pglob)
++#define globfree(pglob) globfree64(pglob)
++
++#define convert_dirent __old_convert_dirent
++#define glob_in_dir __old_glob_in_dir
++
++#undef stat
++#define stat stat64
++#undef __stat
++#define __stat(file, buf) __xstat64 (_STAT_VER, file, buf)
++
++#define GLOB_ATTRIBUTE attribute_compat_text_section
++
++#include <posix/glob.c>
++
++libc_hidden_def (__old_glob64);
++
++compat_symbol (libc, __old_glob64, glob64, GLIBC_2_1);
++#endif
 diff --git a/sysdeps/unix/sysv/linux/s390/pt-longjmp.c 
b/sysdeps/unix/sysv/linux/s390/pt-longjmp.c
 index d324237edd..0221ac2cf5 100644
 --- a/sysdeps/unix/sysv/linux/s390/pt-longjmp.c
@@ -10085,6 +12330,49 @@ index 2daf0c5ef0..ee09fb762b 100644
      }
    else
      ec = -new_pid;
+diff --git a/sysdeps/unix/sysv/linux/wordsize-64/globfree64.c 
b/sysdeps/unix/sysv/linux/wordsize-64/globfree64.c
+new file mode 100644
+index 0000000000..af035e1514
+--- /dev/null
++++ b/sysdeps/unix/sysv/linux/wordsize-64/globfree64.c
+@@ -0,0 +1,2 @@
++/* This file is here so sysdeps/gnu/glob64.c doesn't take precedence.  */
++#include <sysdeps/wordsize-64/globfree64.c>
+diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/globfree.c 
b/sysdeps/unix/sysv/linux/x86_64/x32/globfree.c
+new file mode 100644
+index 0000000000..b76a761c17
+--- /dev/null
++++ b/sysdeps/unix/sysv/linux/x86_64/x32/globfree.c
+@@ -0,0 +1 @@
++#include <sysdeps/wordsize-64/globfree.c>
+diff --git a/sysdeps/wordsize-64/glob.c b/sysdeps/wordsize-64/glob.c
+index 082faf1c70..954e8d37e2 100644
+--- a/sysdeps/wordsize-64/glob.c
++++ b/sysdeps/wordsize-64/glob.c
+@@ -4,5 +4,3 @@
+ #undef glob64
+ #undef globfree64
+ weak_alias (glob, glob64)
+-weak_alias (globfree, globfree64)
+-libc_hidden_ver (globfree, globfree64)
+diff --git a/sysdeps/wordsize-64/globfree.c b/sysdeps/wordsize-64/globfree.c
+new file mode 100644
+index 0000000000..ec8c35b489
+--- /dev/null
++++ b/sysdeps/wordsize-64/globfree.c
+@@ -0,0 +1,5 @@
++#define globfree64 __no_globfree64_decl
++#include <posix/globfree.c>
++#undef globfree64
++weak_alias (globfree, globfree64)
++libc_hidden_ver (globfree, globfree64)
+diff --git a/sysdeps/wordsize-64/globfree64.c 
b/sysdeps/wordsize-64/globfree64.c
+new file mode 100644
+index 0000000000..a0f57ff4b3
+--- /dev/null
++++ b/sysdeps/wordsize-64/globfree64.c
+@@ -0,0 +1 @@
++/* globfree64 is in globfree.c */
 diff --git a/sysdeps/x86/cpu-features-offsets.sym 
b/sysdeps/x86/cpu-features-offsets.sym
 index f6739fae81..33dd094e37 100644
 --- a/sysdeps/x86/cpu-features-offsets.sym

-- 
Alioth's /usr/local/bin/git-commit-notice on 
/srv/git.debian.org/git/pkg-glibc/glibc.git

Reply via email to