bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] glob: merge glibc changes into lib/glob.c


From: Paul Eggert
Subject: [PATCH] glob: merge glibc changes into lib/glob.c
Date: Wed, 4 May 2016 09:59:06 -0700

* lib/glob.c (glob_in_dir): Sync with glibc/posix/glob.c,
dated 2016-05-04 12:09:35 2016 +0200.  Here are the changes:
2016-05-04 CVE-2016-1234: glob: Do not copy d_name field of
  struct dirent [BZ #19779]
2016-04-29 glob: Simplify the interface for the GLOB_ALTDIRFUNC
  callback gl_readdir
2015-10-20 Convert miscellaneous function definitions to prototype style
2015-10-20 Convert 113 more function definitions to prototype style
  (files with assertions)
2015-06-12 Fix getlogin_r namespace (bug 18527).
2014-02-10 Use glibc_likely instead __builtin_expect.
2013-10-20 When glob pattern contains a trailing slash match only
  directories. Fixes bug 10278.
2013-09-04 glob: silence -Wattribute warnings
2013-06-07 Avoid use of "register" as optimization hint.
2012-09-25 Use size_t instead of int for internal variables in glob
  (bug 14621)
2011-07-20 Check for overflows in expressions
2011-05-28 Remove unused variable
2011-05-22 Add a few more alloca size checks
2010-03-27 Whitespace fixes
2010-03-27 Fix one more issue with the glob patch
2010-03-24 Fix glob with empty pattern
2008-05-27 Remove useless more "if" tests before "free"
* modules/glob (Depends-on): Add stdint.
---
 ChangeLog    |  29 +++
 lib/glob.c   | 794 ++++++++++++++++++++++++++++++++++++++---------------------
 modules/glob |   1 +
 3 files changed, 540 insertions(+), 284 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index ee9925d..803a008 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,32 @@
+2016-05-04  Paul Eggert  <address@hidden>
+
+       glob: merge glibc changes into lib/glob.c
+       * lib/glob.c (glob_in_dir): Sync with glibc/posix/glob.c,
+       dated 2016-05-04 12:09:35 2016 +0200.  Here are the changes:
+       2016-05-04 CVE-2016-1234: glob: Do not copy d_name field of
+         struct dirent [BZ #19779]
+       2016-04-29 glob: Simplify the interface for the GLOB_ALTDIRFUNC
+         callback gl_readdir
+       2015-10-20 Convert miscellaneous function definitions to prototype style
+       2015-10-20 Convert 113 more function definitions to prototype style
+         (files with assertions)
+       2015-06-12 Fix getlogin_r namespace (bug 18527).
+       2014-02-10 Use glibc_likely instead __builtin_expect.
+       2013-10-20 When glob pattern contains a trailing slash match only
+         directories. Fixes bug 10278.
+       2013-09-04 glob: silence -Wattribute warnings
+       2013-06-07 Avoid use of "register" as optimization hint.
+       2012-09-25 Use size_t instead of int for internal variables in glob
+         (bug 14621)
+       2011-07-20 Check for overflows in expressions
+       2011-05-28 Remove unused variable
+       2011-05-22 Add a few more alloca size checks
+       2010-03-27 Whitespace fixes
+       2010-03-27 Fix one more issue with the glob patch
+       2010-03-24 Fix glob with empty pattern
+       2008-05-27 Remove useless more "if" tests before "free"
+       * modules/glob (Depends-on): Add stdint.
+
 2016-05-01  Paul Eggert  <address@hidden>
 
        mktime: port to stricter signed overflow checking
diff --git a/lib/glob.c b/lib/glob.c
index 52290b2..ff4fee1 100644
--- a/lib/glob.c
+++ b/lib/glob.c
@@ -1,18 +1,19 @@
 /* Copyright (C) 1991-2016 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
+   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.
 
-   This program is distributed in the hope that it will be useful,
+   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 General Public License for more details.
+   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 General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+   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
 /* Don't use __attribute__ __nonnull__ in this compilation unit.  Otherwise gcc
@@ -26,17 +27,17 @@
 #include <errno.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <stdbool.h>
 #include <stddef.h>
+#include <stdint.h>
 
 /* Outcomment the following line for production quality code.  */
 /* #define NDEBUG 1 */
 #include <assert.h>
 
-#include <stdbool.h>
-
 #include <stdio.h>              /* Needed on stupid SunOS for assert.  */
 
-#if !defined _LIBC || !defined GLOB_ONLY_P
+#ifndef GLOB_ONLY_P
 
 #include <unistd.h>
 #if !defined POSIX && defined _POSIX_VERSION
@@ -57,74 +58,8 @@
 #endif
 
 #include <dirent.h>
-
-
-/* In GNU systems, <dirent.h> defines this macro for us.  */
-#ifndef _D_EXACT_NAMLEN
-# define _D_EXACT_NAMLEN(dirent) strlen ((dirent)->d_name)
-#endif
-
-/* When used in the GNU libc the symbol _DIRENT_HAVE_D_TYPE is available
-   if the 'd_type' member for 'struct dirent' is available.
-   HAVE_STRUCT_DIRENT_D_TYPE plays the same role in GNULIB.  */
-#if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE
-/* True if the directory entry D must be of type T.  */
-# define DIRENT_MUST_BE(d, t)   ((d)->d_type == (t))
-
-/* True if the directory entry D might be a symbolic link.  */
-# define DIRENT_MIGHT_BE_SYMLINK(d) \
-    ((d)->d_type == DT_UNKNOWN || (d)->d_type == DT_LNK)
-
-/* True if the directory entry D might be a directory.  */
-# define DIRENT_MIGHT_BE_DIR(d)  \
-    ((d)->d_type == DT_DIR || DIRENT_MIGHT_BE_SYMLINK (d))
-
-#else /* !HAVE_D_TYPE */
-# define DIRENT_MUST_BE(d, t)           false
-# define DIRENT_MIGHT_BE_SYMLINK(d)     true
-# define DIRENT_MIGHT_BE_DIR(d)         true
-#endif /* HAVE_D_TYPE */
-
-/* If the system has the 'struct dirent64' type we use it internally.  */
-#if defined _LIBC && !defined COMPILE_GLOB64
-# if (defined POSIX || defined WINDOWS32) && !defined __GNU_LIBRARY__
-#  define CONVERT_D_INO(d64, d32)
-# else
-#  define CONVERT_D_INO(d64, d32) \
-  (d64)->d_ino = (d32)->d_ino;
-# endif
-
-# ifdef _DIRENT_HAVE_D_TYPE
-#  define CONVERT_D_TYPE(d64, d32) \
-  (d64)->d_type = (d32)->d_type;
-# else
-#  define CONVERT_D_TYPE(d64, d32)
-# endif
-
-# define CONVERT_DIRENT_DIRENT64(d64, d32) \
-  memcpy ((d64)->d_name, (d32)->d_name, _D_EXACT_NAMLEN (d32) + 1);           \
-  CONVERT_D_INO (d64, d32)                                                    \
-  CONVERT_D_TYPE (d64, d32)
-#endif
-
-
-#if (defined POSIX || defined WINDOWS32) && !defined __GNU_LIBRARY__
-/* Posix does not require that the d_ino field be present, and some
-   systems do not provide it. */
-# define REAL_DIR_ENTRY(dp) 1
-#else
-# define REAL_DIR_ENTRY(dp) (dp->d_ino != 0)
-#endif /* POSIX */
-
 #include <stdlib.h>
 #include <string.h>
-
-/* NAME_MAX is usually defined in <dirent.h> or <limits.h>.  */
-#include <limits.h>
-#ifndef NAME_MAX
-# define NAME_MAX (sizeof (((struct dirent *) 0)->d_name))
-#endif
-
 #include <alloca.h>
 
 #ifdef _LIBC
@@ -141,12 +76,14 @@
 # endif
 # define struct_stat64          struct stat64
 #else /* !_LIBC */
+# 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
 # define __alloca               alloca
 # define __readdir              readdir
 # define __glob_pattern_p       glob_pattern_p
+# define COMPILE_GLOB64
 #endif /* _LIBC */
 
 #include <fnmatch.h>
@@ -164,7 +101,110 @@
 
 static const char *next_brace_sub (const char *begin, int flags) __THROWNL;
 
-#endif /* !defined _LIBC || !defined GLOB_ONLY_P */
+/* A representation of a directory entry which does not depend on the
+   layout of struct dirent, or the size of ino_t.  */
+struct readdir_result
+{
+  const char *name;
+# if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE
+  uint8_t type;
+# endif
+  bool skip_entry;
+};
+
+# if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE
+/* Initializer based on the d_type member of struct dirent.  */
+#  define D_TYPE_TO_RESULT(source) (source)->d_type,
+
+/* True if the directory entry D might be a symbolic link.  */
+static bool
+readdir_result_might_be_symlink (struct readdir_result d)
+{
+  return d.type == DT_UNKNOWN || d.type == DT_LNK;
+}
+
+/* True if the directory entry D might be a directory.  */
+static bool
+readdir_result_might_be_dir (struct readdir_result d)
+{
+  return d.type == DT_DIR || readdir_result_might_be_symlink (d);
+}
+# else /* defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE */
+#  define D_TYPE_TO_RESULT(source)
+
+/* If we do not have type information, symbolic links and directories
+   are always a possibility.  */
+
+static bool
+readdir_result_might_be_symlink (struct readdir_result d)
+{
+  return true;
+}
+
+static bool
+readdir_result_might_be_dir (struct readdir_result d)
+{
+  return true;
+}
+
+# endif /* defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE */
+
+# if (defined POSIX || defined WINDOWS32) && !defined __GNU_LIBRARY__
+/* Initializer for skip_entry.  POSIX does not require that the d_ino
+   field be present, and some systems do not provide it. */
+#  define D_INO_TO_RESULT(source) false,
+# else
+#  define D_INO_TO_RESULT(source) (source)->d_ino == 0,
+# endif
+
+/* Construct an initializer for a struct readdir_result object from a
+   struct dirent *.  No copy of the name is made.  */
+#define READDIR_RESULT_INITIALIZER(source) \
+  {                                        \
+    source->d_name,                        \
+    D_TYPE_TO_RESULT (source)              \
+    D_INO_TO_RESULT (source)               \
+  }
+
+#endif /* !defined GLOB_ONLY_P */
+
+/* Call gl_readdir on STREAM.  This macro can be overridden to reduce
+   type safety if an old interface version needs to be supported.  */
+#ifndef GL_READDIR
+# define GL_READDIR(pglob, stream) ((pglob)->gl_readdir (stream))
+#endif
+
+/* Extract name and type from directory entry.  No copy of the name is
+   made.  If SOURCE is NULL, result name is NULL.  Keep in sync with
+   convert_dirent64 below.  */
+static struct readdir_result
+convert_dirent (const struct dirent *source)
+{
+  if (source == NULL)
+    {
+      struct readdir_result result = { NULL, };
+      return result;
+    }
+  struct readdir_result result = READDIR_RESULT_INITIALIZER (source);
+  return result;
+}
+
+#ifndef COMPILE_GLOB64
+/* Like convert_dirent, but works on struct dirent64 instead.  Keep in
+   sync with convert_dirent above.  */
+static struct readdir_result
+convert_dirent64 (const struct dirent64 *source)
+{
+  if (source == NULL)
+    {
+      struct readdir_result result = { NULL, };
+      return result;
+    }
+  struct readdir_result result = READDIR_RESULT_INITIALIZER (source);
+  return result;
+}
+#endif
+
 
 #ifndef attribute_hidden
 # define attribute_hidden
@@ -182,6 +222,10 @@ static const char *next_brace_sub (const char *begin, int 
flags) __THROWNL;
 # define __builtin_expect(expr, expected) (expr)
 #endif
 
+#ifndef __glibc_unlikely
+# define __glibc_unlikely(expr) __builtin_expect (expr, 0)
+#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,
@@ -195,25 +239,20 @@ static const char *next_brace_sub (const char *begin, int 
flags) __THROWNL;
 #  undef closedir
 # endif
 
-# if HAVE_ALLOCA
-/* The OS usually guarantees only one guard page at the bottom of the stack,
-   and a page size can be as small as 4096 bytes.  So we cannot safely
-   allocate anything larger than 4096 bytes.  Also care for the possibility
-   of a few compiler-allocated temporary stack slots.  */
-#  define __libc_use_alloca(n) ((n) < 4032)
-# else
-/* alloca is implemented with malloc, so just use malloc.  */
-#  define __libc_use_alloca(n) 0
-# endif
+/* 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
 
 static int glob_in_dir (const char *pattern, const char *directory,
                         int flags, int (*errfunc) (const char *, int),
-                        glob_t *pglob);
+                        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
+#ifndef 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;
 
@@ -222,7 +261,7 @@ static int collated_compare (const void *, const void *) 
__THROWNL;
 static const char *
 next_brace_sub (const char *cp, int flags)
 {
-  unsigned int depth = 0;
+  size_t depth = 0;
   while (*cp != '\0')
     if ((flags & GLOB_NOESCAPE) == 0 && *cp == '\\')
       {
@@ -242,7 +281,7 @@ next_brace_sub (const char *cp, int flags)
   return *cp != '\0' ? cp : NULL;
 }
 
-#endif /* !defined _LIBC || !defined GLOB_ONLY_P */
+#endif /* !defined GLOB_ONLY_P */
 
 /* Do glob searching for PATTERN, placing results in PGLOB.
    The bits defined above may be set in FLAGS.
@@ -256,20 +295,20 @@ int
 #ifdef GLOB_ATTRIBUTE
 GLOB_ATTRIBUTE
 #endif
-glob (pattern, flags, errfunc, pglob)
-     const char * restrict pattern;
-     int flags;
-     int (*errfunc) (const char *, int);
-     glob_t * restrict pglob;
+glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
+      glob_t *pglob)
 {
   const char *filename;
-  const char *dirname;
+  char *dirname = NULL;
   size_t dirlen;
   int status;
   size_t oldcount;
   int meta;
   int dirname_modified;
+  int malloc_dirname = 0;
   glob_t dirs;
+  int retval = 0;
+  size_t alloca_used = 0;
 
   if (pattern == NULL || pglob == NULL || (flags & ~__GLOB_FLAGS) != 0)
     {
@@ -277,6 +316,11 @@ glob (pattern, flags, errfunc, pglob)
       return -1;
     }
 
+  /* POSIX requires all slashes to be matched.  This means that with
+     a trailing slash we must match only directories.  */
+  if (pattern[0] && pattern[strlen (pattern) - 1] == '/')
+    flags |= GLOB_ONLYDIR;
+
   if (!(flags & GLOB_DOOFFS))
     /* Have to do this so 'globfree' knows where to start freeing.  It
        also makes all the code that uses gl_offs simpler. */
@@ -318,20 +362,24 @@ glob (pattern, flags, errfunc, pglob)
           const char *next;
           const char *rest;
           size_t rest_len;
-#ifdef __GNUC__
-          char onealt[strlen (pattern) - 1];
-#else
-          char *onealt = malloc (strlen (pattern) - 1);
-          if (onealt == NULL)
+          char *onealt;
+          size_t pattern_len = strlen (pattern) - 1;
+          int alloca_onealt = __libc_use_alloca (alloca_used + pattern_len);
+          if (alloca_onealt)
+            onealt = alloca_account (pattern_len, alloca_used);
+          else
             {
-              if (!(flags & GLOB_APPEND))
+              onealt = malloc (pattern_len);
+              if (onealt == NULL)
                 {
-                  pglob->gl_pathc = 0;
-                  pglob->gl_pathv = NULL;
+                  if (!(flags & GLOB_APPEND))
+                    {
+                      pglob->gl_pathc = 0;
+                      pglob->gl_pathv = NULL;
+                    }
+                  return GLOB_NOSPACE;
                 }
-              return GLOB_NOSPACE;
             }
-#endif
 
           /* We know the prefix for all sub-patterns.  */
           alt_start = mempcpy (onealt, pattern, begin - pattern);
@@ -342,9 +390,9 @@ glob (pattern, flags, errfunc, pglob)
           if (next == NULL)
             {
               /* It is an invalid expression.  */
-#ifndef __GNUC__
-              free (onealt);
-#endif
+            illegal_brace:
+              if (__glibc_unlikely (!alloca_onealt))
+                free (onealt);
               return glob (pattern, flags & ~GLOB_BRACE, errfunc, pglob);
             }
 
@@ -354,13 +402,8 @@ glob (pattern, flags, errfunc, pglob)
             {
               rest = next_brace_sub (rest + 1, flags);
               if (rest == NULL)
-                {
-                  /* It is an invalid expression.  */
-#ifndef __GNUC__
-                  free (onealt);
-#endif
-                  return glob (pattern, flags & ~GLOB_BRACE, errfunc, pglob);
-                }
+                /* It is an illegal expression.  */
+                goto illegal_brace;
             }
           /* Please note that we now can be sure the brace expression
              is well-formed.  */
@@ -396,9 +439,8 @@ glob (pattern, flags, errfunc, pglob)
               /* If we got an error, return it.  */
               if (result && result != GLOB_NOMATCH)
                 {
-#ifndef __GNUC__
-                  free (onealt);
-#endif
+                  if (__glibc_unlikely (!alloca_onealt))
+                    free (onealt);
                   if (!(flags & GLOB_APPEND))
                     {
                       globfree (pglob);
@@ -416,9 +458,8 @@ glob (pattern, flags, errfunc, pglob)
               assert (next != NULL);
             }
 
-#ifndef __GNUC__
-          free (onealt);
-#endif
+          if (__glibc_unlikely (!alloca_onealt))
+            free (onealt);
 
           if (pglob->gl_pathc != firstc)
             /* We found some entries.  */
@@ -428,6 +469,29 @@ glob (pattern, flags, errfunc, pglob)
         }
     }
 
+  if (!(flags & GLOB_APPEND))
+    {
+      pglob->gl_pathc = 0;
+      if (!(flags & GLOB_DOOFFS))
+        pglob->gl_pathv = NULL;
+      else
+        {
+          size_t i;
+
+          if (pglob->gl_offs >= ~((size_t) 0) / sizeof (char *))
+            return GLOB_NOSPACE;
+
+          pglob->gl_pathv = malloc ((pglob->gl_offs + 1) * sizeof (char *));
+          if (pglob->gl_pathv == NULL)
+            return GLOB_NOSPACE;
+
+          for (i = 0; i <= pglob->gl_offs; ++i)
+            pglob->gl_pathv[i] = NULL;
+        }
+    }
+
+  oldcount = pglob->gl_pathc + pglob->gl_offs;
+
   /* Find the filename.  */
   filename = strrchr (pattern, '/');
 #if defined __MSDOS__ || defined WINDOWS32
@@ -445,7 +509,7 @@ glob (pattern, flags, errfunc, pglob)
          case is nothing but a notation for a directory.  */
       if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && pattern[0] == '~')
         {
-          dirname = pattern;
+          dirname = (char *) pattern;
           dirlen = strlen (pattern);
 
           /* Set FILENAME to NULL as a special flag.  This is ugly but
@@ -455,11 +519,17 @@ glob (pattern, flags, errfunc, pglob)
         }
       else
         {
+          if (__glibc_unlikely (pattern[0] == '\0'))
+            {
+              dirs.gl_pathv = NULL;
+              goto no_matches;
+            }
+
           filename = pattern;
 #ifdef _AMIGA
-          dirname = "";
+          dirname = (char *) "";
 #else
-          dirname = ".";
+          dirname = (char *) ".";
 #endif
           dirlen = 0;
         }
@@ -469,7 +539,7 @@ glob (pattern, flags, errfunc, pglob)
                && (flags & GLOB_NOESCAPE) == 0))
     {
       /* "/pattern" or "\\/pattern".  */
-      dirname = "/";
+      dirname = (char *) "/";
       dirlen = 1;
       ++filename;
     }
@@ -495,7 +565,15 @@ glob (pattern, flags, errfunc, pglob)
              from "d:/", since "d:" and "d:/" are not the same.*/
         }
 #endif
-      newp = __alloca (dirlen + 1);
+      if (__libc_use_alloca (alloca_used + dirlen + 1))
+        newp = alloca_account (dirlen + 1, alloca_used);
+      else
+        {
+          newp = malloc (dirlen + 1);
+          if (newp == NULL)
+            return GLOB_NOSPACE;
+          malloc_dirname = 1;
+        }
       *((char *) mempcpy (newp, pattern, dirlen)) = '\0';
       dirname = newp;
       ++filename;
@@ -536,29 +614,11 @@ glob (pattern, flags, errfunc, pglob)
               oldcount = pglob->gl_pathc + pglob->gl_offs;
               goto no_matches;
             }
-          return val;
-        }
-    }
-
-  if (!(flags & GLOB_APPEND))
-    {
-      pglob->gl_pathc = 0;
-      if (!(flags & GLOB_DOOFFS))
-        pglob->gl_pathv = NULL;
-      else
-        {
-          size_t i;
-          pglob->gl_pathv = malloc ((pglob->gl_offs + 1) * sizeof (char *));
-          if (pglob->gl_pathv == NULL)
-            return GLOB_NOSPACE;
-
-          for (i = 0; i <= pglob->gl_offs; ++i)
-            pglob->gl_pathv[i] = NULL;
+          retval = val;
+          goto out;
         }
     }
 
-  oldcount = pglob->gl_pathc + pglob->gl_offs;
-
   if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && dirname[0] == '~')
     {
       if (dirname[1] == '\0' || dirname[1] == '/'
@@ -566,7 +626,8 @@ glob (pattern, flags, errfunc, pglob)
               && (dirname[2] == '\0' || dirname[2] == '/')))
         {
           /* Look up home directory.  */
-          const char *home_dir = getenv ("HOME");
+          char *home_dir = getenv ("HOME");
+          int malloc_home_dir = 0;
 # ifdef _AMIGA
           if (home_dir == NULL || home_dir[0] == '\0')
             home_dir = "SYS:";
@@ -597,15 +658,27 @@ glob (pattern, flags, errfunc, pglob)
             {
               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
                    a moderate value.  */
                 buflen = 20;
-              name = __alloca (buflen);
+              if (__libc_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;
+              success = __getlogin_r (name, buflen) == 0;
               if (success)
                 {
                   struct passwd *p;
@@ -613,6 +686,7 @@ glob (pattern, flags, errfunc, pglob)
                   long int pwbuflen = GETPW_R_SIZE_MAX ();
                   char *pwtmpbuf;
                   struct passwd pwbuf;
+                  int malloc_pwtmpbuf = 0;
                   int save = errno;
 
 #    ifndef _LIBC
@@ -621,7 +695,18 @@ glob (pattern, flags, errfunc, pglob)
                        Try a moderate value.  */
                     pwbuflen = 1024;
 #    endif
-                  pwtmpbuf = __alloca (pwbuflen);
+                  if (__libc_use_alloca (alloca_used + pwbuflen))
+                    pwtmpbuf = alloca_account (pwbuflen, alloca_used);
+                  else
+                    {
+                      pwtmpbuf = malloc (pwbuflen);
+                      if (pwtmpbuf == NULL)
+                        {
+                          retval = GLOB_NOSPACE;
+                          goto out;
+                        }
+                      malloc_pwtmpbuf = 1;
+                    }
 
                   while (getpwnam_r (name, &pwbuf, pwtmpbuf, pwbuflen, &p)
                          != 0)
@@ -631,46 +716,117 @@ glob (pattern, flags, errfunc, pglob)
                           p = NULL;
                           break;
                         }
-#    ifdef _LIBC
-                      pwtmpbuf = extend_alloca (pwtmpbuf, pwbuflen,
+
+                      if (!malloc_pwtmpbuf
+                          && __libc_use_alloca (alloca_used
+                                                + 2 * pwbuflen))
+                        pwtmpbuf = extend_alloca_account (pwtmpbuf, pwbuflen,
+                                                          2 * pwbuflen,
+                                                          alloca_used);
+                      else
+                        {
+                          char *newp = realloc (malloc_pwtmpbuf
+                                                ? pwtmpbuf : NULL,
                                                 2 * pwbuflen);
-#    else
-                      pwbuflen *= 2;
-                      pwtmpbuf = __alloca (pwbuflen);
-#    endif
+                          if (newp == NULL)
+                            {
+                              if (__glibc_unlikely (malloc_pwtmpbuf))
+                                free (pwtmpbuf);
+                              retval = GLOB_NOSPACE;
+                              goto out;
+                            }
+                          pwtmpbuf = newp;
+                          pwbuflen = 2 * pwbuflen;
+                          malloc_pwtmpbuf = 1;
+                        }
                       __set_errno (save);
                     }
 #   else
                   p = getpwnam (name);
 #   endif
+                  if (__glibc_unlikely (malloc_name))
+                    free (name);
                   if (p != NULL)
-                    home_dir = p->pw_dir;
+                    {
+                      if (!malloc_pwtmpbuf)
+                        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))
+                            home_dir = alloca_account (home_dir_len,
+                                                       alloca_used);
+                          else
+                            {
+                              home_dir = malloc (home_dir_len);
+                              if (home_dir == NULL)
+                                {
+                                  free (pwtmpbuf);
+                                  retval = GLOB_NOSPACE;
+                                  goto out;
+                                }
+                              malloc_home_dir = 1;
+                            }
+                          memcpy (home_dir, p->pw_dir, home_dir_len);
+
+                          free (pwtmpbuf);
+                        }
+                    }
                 }
             }
           if (home_dir == NULL || home_dir[0] == '\0')
             {
               if (flags & GLOB_TILDE_CHECK)
-                return GLOB_NOMATCH;
+                {
+                  if (__glibc_unlikely (malloc_home_dir))
+                    free (home_dir);
+                  retval = GLOB_NOMATCH;
+                  goto out;
+                }
               else
-                home_dir = "~"; /* No luck.  */
+                home_dir = (char *) "~"; /* No luck.  */
             }
 #  endif /* WINDOWS32 */
 # endif
           /* Now construct the full directory.  */
           if (dirname[1] == '\0')
             {
+              if (__glibc_unlikely (malloc_dirname))
+                free (dirname);
+
               dirname = home_dir;
               dirlen = strlen (dirname);
+              malloc_dirname = malloc_home_dir;
             }
           else
             {
               char *newp;
               size_t home_len = strlen (home_dir);
-              newp = __alloca (home_len + dirlen);
+              int use_alloca = __libc_use_alloca (alloca_used
+                                                  + home_len + dirlen);
+              if (use_alloca)
+                newp = alloca_account (home_len + dirlen, alloca_used);
+              else
+                {
+                  newp = malloc (home_len + dirlen);
+                  if (newp == NULL)
+                    {
+                      if (__glibc_unlikely (malloc_home_dir))
+                        free (home_dir);
+                      retval = GLOB_NOSPACE;
+                      goto out;
+                    }
+                }
+
               mempcpy (mempcpy (newp, home_dir, home_len),
                        &dirname[1], dirlen);
+
+              if (__glibc_unlikely (malloc_dirname))
+                free (dirname);
+
               dirname = newp;
               dirlen += home_len - 1;
+              malloc_dirname = !use_alloca;
             }
           dirname_modified = 1;
         }
@@ -678,8 +834,8 @@ glob (pattern, flags, errfunc, pglob)
       else
         {
           char *end_name = strchr (dirname, '/');
-          const char *user_name;
-          const char *home_dir;
+          char *user_name;
+          int malloc_user_name = 0;
           char *unescape = NULL;
 
           if (!(flags & GLOB_NOESCAPE))
@@ -698,9 +854,18 @@ glob (pattern, flags, errfunc, pglob)
           else
             {
               char *newp;
-              newp = __alloca (end_name - dirname);
-              *((char *) mempcpy (newp, dirname + 1, end_name - dirname))
-                = '\0';
+              if (__libc_use_alloca (alloca_used + (end_name - dirname)))
+                newp = alloca_account (end_name - dirname, alloca_used);
+              else
+                {
+                  newp = malloc (end_name - dirname);
+                  if (newp == NULL)
+                    {
+                      retval = GLOB_NOSPACE;
+                      goto out;
+                    }
+                  malloc_user_name = 1;
+                }
               if (unescape != NULL)
                 {
                   char *p = mempcpy (newp, dirname + 1,
@@ -737,6 +902,7 @@ glob (pattern, flags, errfunc, pglob)
 #  if defined HAVE_GETPWNAM_R || defined _LIBC
             long int buflen = GETPW_R_SIZE_MAX ();
             char *pwtmpbuf;
+            int malloc_pwtmpbuf = 0;
             struct passwd pwbuf;
             int save = errno;
 
@@ -746,7 +912,21 @@ glob (pattern, flags, errfunc, pglob)
                  moderate value.  */
               buflen = 1024;
 #   endif
-            pwtmpbuf = __alloca (buflen);
+            if (__libc_use_alloca (alloca_used + buflen))
+              pwtmpbuf = alloca_account (buflen, alloca_used);
+            else
+              {
+                pwtmpbuf = malloc (buflen);
+                if (pwtmpbuf == NULL)
+                  {
+                  nomem_getpw:
+                    if (__glibc_unlikely (malloc_user_name))
+                      free (user_name);
+                    retval = GLOB_NOSPACE;
+                    goto out;
+                  }
+                malloc_pwtmpbuf = 1;
+              }
 
             while (getpwnam_r (user_name, &pwbuf, pwtmpbuf, buflen, &p) != 0)
               {
@@ -755,40 +935,77 @@ glob (pattern, flags, errfunc, pglob)
                     p = NULL;
                     break;
                   }
-#   ifdef _LIBC
-                pwtmpbuf = extend_alloca (pwtmpbuf, buflen, 2 * buflen);
-#   else
-                buflen *= 2;
-                pwtmpbuf = __alloca (buflen);
-#   endif
+                if (!malloc_pwtmpbuf
+                    && __libc_use_alloca (alloca_used + 2 * buflen))
+                  pwtmpbuf = extend_alloca_account (pwtmpbuf, buflen,
+                                                    2 * buflen, alloca_used);
+                else
+                  {
+                    char *newp = realloc (malloc_pwtmpbuf ? pwtmpbuf : NULL,
+                                          2 * buflen);
+                    if (newp == NULL)
+                      {
+                        if (__glibc_unlikely (malloc_pwtmpbuf))
+                          free (pwtmpbuf);
+                        goto nomem_getpw;
+                      }
+                    pwtmpbuf = newp;
+                    malloc_pwtmpbuf = 1;
+                  }
                 __set_errno (save);
               }
 #  else
             p = getpwnam (user_name);
 #  endif
+
+            if (__glibc_unlikely (malloc_user_name))
+              free (user_name);
+
+            /* If we found a home directory use this.  */
             if (p != NULL)
-              home_dir = p->pw_dir;
+              {
+                size_t home_len = strlen (p->pw_dir);
+                size_t rest_len = end_name == NULL ? 0 : strlen (end_name);
+
+                if (__glibc_unlikely (malloc_dirname))
+                  free (dirname);
+                malloc_dirname = 0;
+
+                if (__libc_use_alloca (alloca_used + home_len + rest_len + 1))
+                  dirname = alloca_account (home_len + rest_len + 1,
+                                            alloca_used);
+                else
+                  {
+                    dirname = malloc (home_len + rest_len + 1);
+                    if (dirname == NULL)
+                      {
+                        if (__glibc_unlikely (malloc_pwtmpbuf))
+                          free (pwtmpbuf);
+                        retval = GLOB_NOSPACE;
+                        goto out;
+                      }
+                    malloc_dirname = 1;
+                  }
+                *((char *) mempcpy (mempcpy (dirname, p->pw_dir, home_len),
+                                    end_name, rest_len)) = '\0';
+
+                dirlen = home_len + rest_len;
+                dirname_modified = 1;
+
+                if (__glibc_unlikely (malloc_pwtmpbuf))
+                  free (pwtmpbuf);
+              }
             else
-              home_dir = NULL;
+              {
+                if (__glibc_unlikely (malloc_pwtmpbuf))
+                  free (pwtmpbuf);
+
+                if (flags & GLOB_TILDE_CHECK)
+                  /* We have to regard it as an error if we cannot find the
+                     home directory.  */
+                  return GLOB_NOMATCH;
+              }
           }
-          /* If we found a home directory use this.  */
-          if (home_dir != NULL)
-            {
-              char *newp;
-              size_t home_len = strlen (home_dir);
-              size_t rest_len = end_name == NULL ? 0 : strlen (end_name);
-              newp = __alloca (home_len + rest_len + 1);
-              *((char *) mempcpy (mempcpy (newp, home_dir, home_len),
-                                  end_name, rest_len)) = '\0';
-              dirname = newp;
-              dirlen = home_len + rest_len;
-              dirname_modified = 1;
-            }
-          else
-            if (flags & GLOB_TILDE_CHECK)
-              /* We have to regard it as an error if we cannot find the
-                 home directory.  */
-              return GLOB_NOMATCH;
         }
 # endif /* Not Amiga && not WINDOWS32.  */
     }
@@ -807,12 +1024,11 @@ glob (pattern, flags, errfunc, pglob)
                   && S_ISDIR (st.st_mode))
                : (__stat64 (dirname, &st64) == 0 && S_ISDIR (st64.st_mode)))))
         {
-          int newcount = pglob->gl_pathc + pglob->gl_offs;
+          size_t newcount = pglob->gl_pathc + pglob->gl_offs;
           char **new_gl_pathv;
 
-          new_gl_pathv
-            = realloc (pglob->gl_pathv, (newcount + 1 + 1) * sizeof (char *));
-          if (new_gl_pathv == NULL)
+          if (newcount > UINTPTR_MAX - (1 + 1)
+              || newcount + 1 + 1 > ~((size_t) 0) / sizeof (char *))
             {
             nospace:
               free (pglob->gl_pathv);
@@ -820,6 +1036,11 @@ glob (pattern, flags, errfunc, pglob)
               pglob->gl_pathc = 0;
               return GLOB_NOSPACE;
             }
+
+          new_gl_pathv = realloc (pglob->gl_pathv,
+                                  (newcount + 1 + 1) * sizeof (char *));
+          if (new_gl_pathv == NULL)
+            goto nospace;
           pglob->gl_pathv = new_gl_pathv;
 
           if (flags & GLOB_MARK)
@@ -873,7 +1094,7 @@ glob (pattern, flags, errfunc, pglob)
             *(char *) &dirname[--dirlen] = '\0';
         }
 
-      if (__builtin_expect ((flags & GLOB_ALTDIRFUNC) != 0, 0))
+      if (__glibc_unlikely ((flags & GLOB_ALTDIRFUNC) != 0))
         {
           /* Use the alternative access functions also in the recursive
              call.  */
@@ -901,7 +1122,7 @@ glob (pattern, flags, errfunc, pglob)
          appending the results to PGLOB.  */
       for (i = 0; i < dirs.gl_pathc; ++i)
         {
-          int old_pathc;
+          size_t old_pathc;
 
 #ifdef SHELL
           {
@@ -920,7 +1141,7 @@ glob (pattern, flags, errfunc, pglob)
           status = glob_in_dir (filename, dirs.gl_pathv[i],
                                 ((flags | GLOB_APPEND)
                                  & ~(GLOB_NOCHECK | GLOB_NOMAGIC)),
-                                errfunc, pglob);
+                                errfunc, pglob, alloca_used);
           if (status == GLOB_NOMATCH)
             /* No matches in this directory.  Try the next.  */
             continue;
@@ -956,16 +1177,21 @@ glob (pattern, flags, errfunc, pglob)
           /* No matches.  */
           if (flags & GLOB_NOCHECK)
             {
-              int newcount = pglob->gl_pathc + pglob->gl_offs;
+              size_t newcount = pglob->gl_pathc + pglob->gl_offs;
               char **new_gl_pathv;
 
-              new_gl_pathv = realloc (pglob->gl_pathv,
-                                      (newcount + 2) * sizeof (char *));
-              if (new_gl_pathv == NULL)
+              if (newcount > UINTPTR_MAX - 2
+                  || newcount + 2 > ~((size_t) 0) / sizeof (char *))
                 {
+                nospace2:
                   globfree (&dirs);
                   return GLOB_NOSPACE;
                 }
+
+              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);
@@ -994,7 +1220,7 @@ glob (pattern, flags, errfunc, pglob)
     }
   else
     {
-      int old_pathc = pglob->gl_pathc;
+      size_t old_pathc = pglob->gl_pathc;
       int orig_flags = flags;
 
       if (meta & 2)
@@ -1020,7 +1246,8 @@ glob (pattern, flags, errfunc, pglob)
         }
       if (dirname_modified)
         flags &= ~(GLOB_NOCHECK | GLOB_NOMAGIC);
-      status = glob_in_dir (filename, dirname, flags, errfunc, pglob);
+      status = glob_in_dir (filename, dirname, flags, errfunc, pglob,
+                            alloca_used);
       if (status != 0)
         {
           if (status == GLOB_NOMATCH && flags != orig_flags
@@ -1083,26 +1310,28 @@ glob (pattern, flags, errfunc, pglob)
              sizeof (char *), collated_compare);
     }
 
-  return 0;
+ out:
+  if (__glibc_unlikely (malloc_dirname))
+    free (dirname);
+
+  return retval;
 }
 #if defined _LIBC && !defined glob
 libc_hidden_def (glob)
 #endif
 
 
-#if !defined _LIBC || !defined GLOB_ONLY_P
+#ifndef GLOB_ONLY_P
 
 /* Free storage allocated in PGLOB by a previous 'glob' call.  */
 void
-globfree (pglob)
-     register glob_t *pglob;
+globfree (glob_t *pglob)
 {
   if (pglob->gl_pathv != NULL)
     {
       size_t i;
       for (i = 0; i < pglob->gl_pathc; ++i)
-        if (pglob->gl_pathv[pglob->gl_offs + i] != NULL)
-          free (pglob->gl_pathv[pglob->gl_offs + i]);
+        free (pglob->gl_pathv[pglob->gl_offs + i]);
       free (pglob->gl_pathv);
       pglob->gl_pathv = NULL;
     }
@@ -1136,7 +1365,7 @@ collated_compare (const void *a, const void *b)
 static int
 prefix_array (const char *dirname, char **array, size_t n)
 {
-  register size_t i;
+  size_t i;
   size_t dirlen = strlen (dirname);
 #if defined __MSDOS__ || defined WINDOWS32
   int sep_char = '/';
@@ -1189,13 +1418,11 @@ prefix_array (const char *dirname, char **array, size_t 
n)
 
 
 /* We must not compile this function twice.  */
-#if !defined _LIBC || !defined NO_GLOB_PATTERN_P
+#ifndef NO_GLOB_PATTERN_P
 int
-__glob_pattern_type (pattern, quote)
-     const char *pattern;
-     int quote;
+__glob_pattern_type (const char *pattern, int quote)
 {
-  register const char *p;
+  const char *p;
   int ret = 0;
 
   for (p = pattern; *p != '\0'; ++p)
@@ -1230,9 +1457,7 @@ __glob_pattern_type (pattern, quote)
 /* Return nonzero if PATTERN contains any metacharacters.
    Metacharacters can be quoted with backslashes if QUOTE is nonzero.  */
 int
-__glob_pattern_p (pattern, quote)
-     const char *pattern;
-     int quote;
+__glob_pattern_p (const char *pattern, int quote)
 {
   return __glob_pattern_type (pattern, quote) == 1;
 }
@@ -1241,16 +1466,13 @@ weak_alias (__glob_pattern_p, glob_pattern_p)
 # endif
 #endif
 
-#endif /* !GLOB_ONLY_P */
-
 
-#if !defined _LIBC || !defined GLOB_ONLY_P
 /* We put this in a separate function mainly to allow the memory
    allocated with alloca to be recycled.  */
 static int
 __attribute_noinline__
 link_exists2_p (const char *dir, size_t dirlen, const char *fname,
-                glob_t *pglob
+               glob_t *pglob
 # if !defined _LIBC && !HAVE_FSTATAT
                 , int flags
 # endif
@@ -1292,7 +1514,7 @@ link_exists_p (int dfd, const char *dir, size_t dirlen, 
const char *fname,
   return link_exists2_p (dir, dirlen, fname, pglob, flags);
 # endif
 }
-#endif
+#endif /* !defined GLOB_ONLY_P */
 
 
 /* Like 'glob', but PATTERN is a final pathname component,
@@ -1302,7 +1524,7 @@ link_exists_p (int dfd, const char *dir, size_t dirlen, 
const char *fname,
 static int
 glob_in_dir (const char *pattern, const char *directory, int flags,
              int (*errfunc) (const char *, int),
-             glob_t *pglob)
+             glob_t *pglob, size_t alloca_used)
 {
   size_t dirlen = strlen (directory);
   void *stream = NULL;
@@ -1317,12 +1539,13 @@ glob_in_dir (const char *pattern, const char 
*directory, int flags,
   struct globnames *names = &init_names;
   struct globnames *names_alloca = &init_names;
   size_t nfound = 0;
-  size_t allocasize = sizeof (init_names);
   size_t cur = 0;
   int meta;
   int save;
   int result;
 
+  alloca_used += sizeof (init_names);
+
   init_names.next = NULL;
   init_names.count = INITIAL_COUNT;
 
@@ -1338,20 +1561,36 @@ glob_in_dir (const char *pattern, const char 
*directory, int flags,
     {
       /* Since we use the normal file functions we can also use stat()
          to verify the file is there.  */
-      struct stat st;
-      struct_stat64 st64;
+      union
+      {
+        struct stat st;
+        struct_stat64 st64;
+      } ust;
       size_t patlen = strlen (pattern);
-      char *fullname = __alloca (dirlen + 1 + patlen + 1);
+      int alloca_fullname = __libc_use_alloca (alloca_used
+                                               + dirlen + 1 + patlen + 1);
+      char *fullname;
+      if (alloca_fullname)
+        fullname = alloca_account (dirlen + 1 + patlen + 1, alloca_used);
+      else
+        {
+          fullname = malloc (dirlen + 1 + patlen + 1);
+          if (fullname == NULL)
+            return GLOB_NOSPACE;
+        }
 
       mempcpy (mempcpy (mempcpy (fullname, directory, dirlen),
                         "/", 1),
                pattern, patlen + 1);
       if ((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
-           ? (*pglob->gl_stat) (fullname, &st)
-           : __stat64 (fullname, &st64)) == 0)
+           ? (*pglob->gl_stat) (fullname, &ust.st)
+           : __stat64 (fullname, &ust.st64)) == 0)
         /* We found this file to be existing.  Now tell the rest
            of the function to copy this name into the result.  */
         flags |= GLOB_NOCHECK;
+
+      if (__glibc_unlikely (!alloca_fullname))
+        free (fullname);
     }
   else
     {
@@ -1379,56 +1618,36 @@ glob_in_dir (const char *pattern, const char 
*directory, int flags,
 
           while (1)
             {
-              const char *name;
-              size_t len;
-#if defined _LIBC && !defined COMPILE_GLOB64
-              struct dirent64 *d;
-              union
-                {
-                  struct dirent64 d64;
-                  char room [offsetof (struct dirent64, d_name[0])
-                             + NAME_MAX + 1];
-                }
-              d64buf;
-
-              if (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0))
-                {
-                  struct dirent *d32 = (*pglob->gl_readdir) (stream);
-                  if (d32 != NULL)
-                    {
-                      CONVERT_DIRENT_DIRENT64 (&d64buf.d64, d32);
-                      d = &d64buf.d64;
-                    }
-                  else
-                    d = NULL;
-                }
-              else
-                d = __readdir64 (stream);
+              struct readdir_result d;
+              {
+                if (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0))
+                  d = convert_dirent (GL_READDIR (pglob, stream));
+                else
+                  {
+#ifdef COMPILE_GLOB64
+                    d = convert_dirent (__readdir (stream));
 #else
-              struct dirent *d = (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
-                                  ? ((struct dirent *)
-                                     (*pglob->gl_readdir) (stream))
-                                  : __readdir (stream));
+                    d = convert_dirent64 (__readdir64 (stream));
 #endif
-              if (d == NULL)
+                  }
+              }
+              if (d.name == NULL)
                 break;
-              if (! REAL_DIR_ENTRY (d))
+              if (d.skip_entry)
                 continue;
 
               /* If we shall match only directories use the information
                  provided by the dirent call if possible.  */
-              if ((flags & GLOB_ONLYDIR) && !DIRENT_MIGHT_BE_DIR (d))
+              if ((flags & GLOB_ONLYDIR) && !readdir_result_might_be_dir (d))
                 continue;
 
-              name = d->d_name;
-
-              if (fnmatch (pattern, name, fnm_flags) == 0)
+              if (fnmatch (pattern, d.name, fnm_flags) == 0)
                 {
                   /* If the file we found is a symlink we have to
                      make sure the target file exists.  */
-                  if (!DIRENT_MIGHT_BE_SYMLINK (d)
-                      || link_exists_p (dfd, directory, dirlen, name, pglob,
-                                        flags))
+                  if (!readdir_result_might_be_symlink (d)
+                      || link_exists_p (dfd, directory, dirlen, d.name,
+                                        pglob, flags))
                     {
                       if (cur == names->count)
                         {
@@ -1437,9 +1656,9 @@ glob_in_dir (const char *pattern, const char *directory, 
int flags,
                           size_t size = (sizeof (struct globnames)
                                          + ((count - INITIAL_COUNT)
                                             * sizeof (char *)));
-                          allocasize += size;
-                          if (__libc_use_alloca (allocasize))
-                            newnames = names_alloca = __alloca (size);
+                          if (__libc_use_alloca (alloca_used + size))
+                            newnames = names_alloca
+                              = alloca_account (size, alloca_used);
                           else if ((newnames = malloc (size))
                                    == NULL)
                             goto memory_error;
@@ -1448,12 +1667,10 @@ glob_in_dir (const char *pattern, const char 
*directory, int flags,
                           names = newnames;
                           cur = 0;
                         }
-                      len = _D_EXACT_NAMLEN (d);
-                      names->name[cur] = malloc (len + 1);
+                      names->name[cur] = strdup (d.name);
                       if (names->name[cur] == NULL)
                         goto memory_error;
-                      *((char *) mempcpy (names->name[cur++], name, len))
-                        = '\0';
+                      ++cur;
                       ++nfound;
                     }
                 }
@@ -1474,11 +1691,20 @@ glob_in_dir (const char *pattern, const char 
*directory, int flags,
   result = GLOB_NOMATCH;
   if (nfound != 0)
     {
-      char **new_gl_pathv
+      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 *)))
+        goto memory_error;
+
+      new_gl_pathv
         = realloc (pglob->gl_pathv,
                    (pglob->gl_pathc + pglob->gl_offs + nfound + 1)
                    * sizeof (char *));
-      result = 0;
 
       if (new_gl_pathv == NULL)
         {
@@ -1544,7 +1770,7 @@ glob_in_dir (const char *pattern, const char *directory, 
int flags,
   if (stream != NULL)
     {
       save = errno;
-      if (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0))
+      if (__glibc_unlikely (flags & GLOB_ALTDIRFUNC))
         (*pglob->gl_closedir) (stream);
       else
         closedir (stream);
diff --git a/modules/glob b/modules/glob
index cef81cc..919d7fc 100644
--- a/modules/glob
+++ b/modules/glob
@@ -25,6 +25,7 @@ mempcpy         [test -n "$GLOB_H"]
 opendir         [test -n "$GLOB_H"]
 readdir         [test -n "$GLOB_H"]
 stdbool         [test -n "$GLOB_H"]
+stdint          [test -n "$GLOB_H"]
 strdup          [test -n "$GLOB_H"]
 sys_stat        [test -n "$GLOB_H"]
 unistd          [test -n "$GLOB_H"]
-- 
2.5.5





reply via email to

[Prev in Thread] Current Thread [Next in Thread]