about summary refs log tree commit diff
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@gmail.com>2011-05-22 23:04:16 -0400
committerUlrich Drepper <drepper@gmail.com>2011-05-22 23:04:16 -0400
commitf2962a71959fd254a7a223437ca4b63b9e81130c (patch)
treeb4af7d4052ad4aa3ee15b9eee51b590680e5d2a6
parentde7ce8f171b88b2db025fdb6c8cca89c16e541dc (diff)
downloadglibc-f2962a71959fd254a7a223437ca4b63b9e81130c.tar.gz
glibc-f2962a71959fd254a7a223437ca4b63b9e81130c.tar.xz
glibc-f2962a71959fd254a7a223437ca4b63b9e81130c.zip
Add a few more alloca size checks
-rw-r--r--ChangeLog8
-rw-r--r--NEWS8
-rw-r--r--nis/nss_nis/nis-alias.c43
-rw-r--r--nscd/nscd_getserv_r.c59
-rw-r--r--posix/glob.c363
5 files changed, 370 insertions, 111 deletions
diff --git a/ChangeLog b/ChangeLog
index eb321b7701..9f2a02f3e6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
 2011-05-22  Ulrich Drepper  <drepper@gmail.com>
 
+	[BZ #12671]
+	* nis/nss_nis/nis-alias.c (_nss_nis_getaliasbyname_r): Use malloc in
+	some situations.
+	* nscd/nscd_getserv_r.c (nscd_getserv_r): Likewise.
+	* posix/glob.c (glob_in_dir): Take additional parameter alloca_used.
+	add in in __libc_use_alloca calls.  Adjust callers.
+	(glob): Use malloc in some situations.
+
 	* elf/dl-runtime.c (_dl_profile_fixup): Also store LA_SYMB_NOPLTENTER
 	and LA_SYMB_NOPLTEXIT in flags which are passed to pltenter and
 	pltexit.
diff --git a/NEWS b/NEWS
index 90ccee7df8..f3150f2aa5 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,4 @@
-GNU C Library NEWS -- history of user-visible changes.  2011-5-21
+GNU C Library NEWS -- history of user-visible changes.  2011-5-22
 Copyright (C) 1992-2009, 2010, 2011 Free Software Foundation, Inc.
 See the end for copying conditions.
 
@@ -15,9 +15,9 @@ Version 2.14
   12158, 12178, 12200, 12346, 12393, 12420, 12432, 12445, 12449, 12453,
   12454, 12460, 12469, 12489, 12509, 12510, 12511, 12518, 12527, 12541,
   12545, 12551, 12582, 12583, 12587, 12597, 12601, 12611, 12625, 12626,
-  12631, 12650, 12653, 12655, 12660, 12681, 12685, 12711, 12713, 12714,
-  12717, 12723, 12724, 12734, 12738, 12746, 12766, 12775, 12777, 12782,
-  12788, 12792
+  12631, 12650, 12653, 12655, 12660, 12671, 12681, 12685, 12711, 12713,
+  12714, 12717, 12723, 12724, 12734, 12738, 12746, 12766, 12775, 12777,
+  12782, 12788, 12792
 
 * The RPC implementation in libc is obsoleted.  Old programs keep working
   but new programs cannot be linked with the routines in libc anymore.
diff --git a/nis/nss_nis/nis-alias.c b/nis/nss_nis/nis-alias.c
index 9286e36ba6..cfe4097ec8 100644
--- a/nis/nss_nis/nis-alias.c
+++ b/nis/nss_nis/nis-alias.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996-2002, 2003, 2006 Free Software Foundation, Inc.
+/* Copyright (C) 1996-2002, 2003, 2006, 2011 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996.
 
@@ -142,10 +142,10 @@ internal_nis_getaliasent_r (struct aliasent *alias, char *buffer,
       int yperr;
 
       if (new_start)
-        yperr = yp_first (domain, "mail.aliases", &outkey, &keylen, &result,
+	yperr = yp_first (domain, "mail.aliases", &outkey, &keylen, &result,
 			  &len);
       else
-        yperr = yp_next (domain, "mail.aliases", oldkey, oldkeylen, &outkey,
+	yperr = yp_next (domain, "mail.aliases", oldkey, oldkeylen, &outkey,
 			 &keylen, &result, &len);
 
       if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
@@ -153,20 +153,20 @@ internal_nis_getaliasent_r (struct aliasent *alias, char *buffer,
 	  enum nss_status retval = yperr2nss (yperr);
 
 	  if (retval == NSS_STATUS_TRYAGAIN)
-            *errnop = errno;
-          return retval;
-        }
+	    *errnop = errno;
+	  return retval;
+	}
 
       if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
-        {
+	{
 	  free (result);
-          *errnop = ERANGE;
-          return NSS_STATUS_TRYAGAIN;
-        }
+	  *errnop = ERANGE;
+	  return NSS_STATUS_TRYAGAIN;
+	}
       char *p = strncpy (buffer, result, len);
       buffer[len] = '\0';
       while (isspace (*p))
-        ++p;
+	++p;
       free (result);
 
       parse_res = _nss_nis_parse_aliasent (outkey, p, alias, buffer,
@@ -213,13 +213,25 @@ _nss_nis_getaliasbyname_r (const char *name, struct aliasent *alias,
       return NSS_STATUS_UNAVAIL;
     }
 
-  size_t namlen = strlen (name);
-  char name2[namlen + 1];
-
   char *domain;
   if (__builtin_expect (yp_get_default_domain (&domain), 0))
     return NSS_STATUS_UNAVAIL;
 
+  size_t namlen = strlen (name);
+  char *name2;
+  int use_alloca = __libc_use_alloca (namlen + 1);
+  if (use_alloca)
+    name2 = __alloca (namlen + 1);
+  else
+    {
+      name2 = malloc (namlen + 1);
+      if (name2 == NULL)
+	{
+	  *errnop = ENOMEM;
+	  return NSS_STATUS_TRYAGAIN;
+	}
+    }
+
   /* Convert name to lowercase.  */
   size_t i;
   for (i = 0; i < namlen; ++i)
@@ -230,6 +242,9 @@ _nss_nis_getaliasbyname_r (const char *name, struct aliasent *alias,
   int len;
   int yperr = yp_match (domain, "mail.aliases", name2, namlen, &result, &len);
 
+  if (!use_alloca)
+    free (name2);
+
   if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
     {
       enum nss_status retval = yperr2nss (yperr);
diff --git a/nscd/nscd_getserv_r.c b/nscd/nscd_getserv_r.c
index dce4165482..de96a5757b 100644
--- a/nscd/nscd_getserv_r.c
+++ b/nscd/nscd_getserv_r.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007, 2009 Free Software Foundation, Inc.
+/* Copyright (C) 2007, 2009, 2011 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2007.
 
@@ -17,6 +17,7 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
+#include <assert.h>
 #include <errno.h>
 #include <string.h>
 #include <not-cancel.h>
@@ -80,6 +81,7 @@ nscd_getserv_r (const char *crit, size_t critlen, const char *proto,
 {
   int gc_cycle;
   int nretries = 0;
+  size_t alloca_used = 0;
 
   /* If the mapping is available, try to search there instead of
      communicating with the nscd.  */
@@ -88,13 +90,23 @@ nscd_getserv_r (const char *crit, size_t critlen, const char *proto,
 			       &gc_cycle);
   size_t protolen = proto == NULL ? 0 : strlen (proto);
   size_t keylen = critlen + 1 + protolen + 1;
-  char *key = alloca (keylen);
+  int alloca_key = __libc_use_alloca (keylen);
+  char *key;
+  if (alloca_key)
+    key = alloca_account (keylen, alloca_used);
+  else
+    {
+      key = malloc (keylen);
+      if (key == NULL)
+	return -1;
+    }
   memcpy (__mempcpy (__mempcpy (key, crit, critlen),
 		     "/", 1), proto ?: "", protolen + 1);
 
  retry:;
   const char *s_name = NULL;
   const char *s_proto = NULL;
+  int alloca_aliases_len = 0;
   const uint32_t *aliases_len = NULL;
   const char *aliases_list = NULL;
   int retval = -1;
@@ -136,8 +148,22 @@ nscd_getserv_r (const char *crit, size_t critlen, const char *proto,
 	  if (((uintptr_t) aliases_len & (__alignof__ (*aliases_len) - 1))
 	      != 0)
 	    {
-	      uint32_t *tmp = alloca (serv_resp.s_aliases_cnt
-				      * sizeof (uint32_t));
+	      uint32_t *tmp;
+	      alloca_aliases_len
+		= __libc_use_alloca (alloca_used
+				     + (serv_resp.s_aliases_cnt
+					* sizeof (uint32_t)));
+	      if (alloca_aliases_len)
+		tmp = __alloca (serv_resp.s_aliases_cnt * sizeof (uint32_t));
+	      else
+		{
+		  tmp = malloc (serv_resp.s_aliases_cnt * sizeof (uint32_t));
+		  if (tmp == NULL)
+		    {
+		      retval = ENOMEM;
+		      goto out;
+		    }
+		}
 	      aliases_len = memcpy (tmp, aliases_len,
 				    serv_resp.s_aliases_cnt
 				    * sizeof (uint32_t));
@@ -217,8 +243,24 @@ nscd_getserv_r (const char *crit, size_t critlen, const char *proto,
 
 	  if (serv_resp.s_aliases_cnt > 0)
 	    {
-	      aliases_len = alloca (serv_resp.s_aliases_cnt
-				    * sizeof (uint32_t));
+	      assert (alloca_aliases_len == 0);
+	      alloca_aliases_len
+		= __libc_use_alloca (alloca_used
+				     + (serv_resp.s_aliases_cnt
+					* sizeof (uint32_t)));
+	      if (alloca_aliases_len)
+		aliases_len = alloca (serv_resp.s_aliases_cnt
+				      * sizeof (uint32_t));
+	      else
+		{
+		  aliases_len = malloc (serv_resp.s_aliases_cnt
+					* sizeof (uint32_t));
+		  if (aliases_len == NULL)
+		    {
+		      retval = ENOMEM;
+		      goto out_close;
+		    }
+		}
 	      vec[n].iov_base = (void *) aliases_len;
 	      vec[n].iov_len = serv_resp.s_aliases_cnt * sizeof (uint32_t);
 
@@ -329,5 +371,10 @@ nscd_getserv_r (const char *crit, size_t critlen, const char *proto,
 	goto retry;
     }
 
+  if (!alloca_aliases_len)
+    free ((void *) aliases_len);
+  if (!alloca_key)
+    free (key);
+
   return retval;
 }
diff --git a/posix/glob.c b/posix/glob.c
index 6df083a67a..79b6e503a7 100644
--- a/posix/glob.c
+++ b/posix/glob.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991-2002, 2003, 2004, 2005, 2006, 2007, 2008, 2010
+/* Copyright (C) 1991-2002, 2003, 2004, 2005, 2006, 2007, 2008, 2010, 2011
    Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
@@ -199,7 +199,7 @@ static const char *next_brace_sub (const char *begin, int flags) __THROW;
 
 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;
 
@@ -253,13 +253,18 @@ glob (pattern, flags, errfunc, pglob)
      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;
+#ifdef _LIBC
+  size_t alloca_used = 0;
+#endif
 
   if (pattern == NULL || pglob == NULL || (flags & ~__GLOB_FLAGS) != 0)
     {
@@ -308,20 +313,26 @@ 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 = (char *) malloc (strlen (pattern) - 1);
-	  if (onealt == NULL)
+	  char *onealt;
+	  size_t pattern_len = strlen (pattern) - 1;
+#ifdef _LIBC
+	  int alloca_onealt = __libc_use_alloca (alloca_used + pattern_len);
+	  if (alloca_onealt)
+	    onealt = alloca_account (pattern_len, alloca_used);
+	  else
+#endif
 	    {
-	      if (!(flags & GLOB_APPEND))
+	      onealt = (char *) 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);
@@ -332,9 +343,11 @@ glob (pattern, flags, errfunc, pglob)
 	  if (next == NULL)
 	    {
 	      /* It is an illegal expression.  */
-#ifndef __GNUC__
-	      free (onealt);
+	    illegal_brace:
+#ifdef _LIBC
+	      if (__builtin_expect (!alloca_onealt, 0))
 #endif
+		free (onealt);
 	      return glob (pattern, flags & ~GLOB_BRACE, errfunc, pglob);
 	    }
 
@@ -344,13 +357,8 @@ glob (pattern, flags, errfunc, pglob)
 	    {
 	      rest = next_brace_sub (rest + 1, flags);
 	      if (rest == NULL)
-		{
-		  /* It is an illegal 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.  */
@@ -386,9 +394,10 @@ glob (pattern, flags, errfunc, pglob)
 	      /* If we got an error, return it.  */
 	      if (result && result != GLOB_NOMATCH)
 		{
-#ifndef __GNUC__
-		  free (onealt);
+#ifdef _LIBC
+		  if (__builtin_expect (!alloca_onealt, 0))
 #endif
+		    free (onealt);
 		  if (!(flags & GLOB_APPEND))
 		    {
 		      globfree (pglob);
@@ -406,9 +415,10 @@ glob (pattern, flags, errfunc, pglob)
 	      assert (next != NULL);
 	    }
 
-#ifndef __GNUC__
-	  free (onealt);
+#ifdef _LIBC
+	  if (__builtin_expect (!alloca_onealt, 0))
 #endif
+	    free (onealt);
 
 	  if (pglob->gl_pathc != firstc)
 	    /* We found some entries.  */
@@ -455,7 +465,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
@@ -473,9 +483,9 @@ glob (pattern, flags, errfunc, pglob)
 
 	  filename = pattern;
 #ifdef _AMIGA
-	  dirname = "";
+	  dirname = (char *) "";
 #else
-	  dirname = ".";
+	  dirname = (char *) ".";
 #endif
 	  dirlen = 0;
 	}
@@ -485,7 +495,7 @@ glob (pattern, flags, errfunc, pglob)
 	       && (flags & GLOB_NOESCAPE) == 0))
     {
       /* "/pattern" or "\\/pattern".  */
-      dirname = "/";
+      dirname = (char *) "/";
       dirlen = 1;
       ++filename;
     }
@@ -511,7 +521,17 @@ glob (pattern, flags, errfunc, pglob)
 	     from "d:/", since "d:" and "d:/" are not the same.*/
 	}
 #endif
-      newp = (char *) __alloca (dirlen + 1);
+#ifdef _LIBC
+      if (__libc_use_alloca (alloca_used + dirlen + 1))
+	newp = alloca_account (dirlen + 1, alloca_used);
+      else
+#endif
+	{
+	  newp = malloc (dirlen + 1);
+	  if (newp == NULL)
+	    return GLOB_NOSPACE;
+	  malloc_dirname = 1;
+	}
       *((char *) mempcpy (newp, pattern, dirlen)) = '\0';
       dirname = newp;
       ++filename;
@@ -551,7 +571,8 @@ glob (pattern, flags, errfunc, pglob)
 	      oldcount = pglob->gl_pathc + pglob->gl_offs;
 	      goto no_matches;
 	    }
-	  return val;
+	  retval = val;
+	  goto out;
 	}
     }
 
@@ -563,7 +584,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:";
@@ -582,7 +604,7 @@ glob (pattern, flags, errfunc, pglob)
 		/* `sysconf' does not support _SC_LOGIN_NAME_MAX.  Try
 		   a moderate value.  */
 		buflen = 20;
-	      name = (char *) __alloca (buflen);
+	      name = alloca_account (buflen, alloca_used);
 
 	      success = getlogin_r (name, buflen) == 0;
 	      if (success)
@@ -592,6 +614,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
@@ -600,7 +623,18 @@ glob (pattern, flags, errfunc, pglob)
 		       Try a moderate value.  */
 		    pwbuflen = 1024;
 #    endif
-		  pwtmpbuf = (char *) __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)
@@ -610,46 +644,115 @@ 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 = (char *) __alloca (pwbuflen);
-#    endif
+			  if (newp == NULL)
+			    {
+			      if (__builtin_expect (malloc_pwtmpbuf, 0))
+				free (pwtmpbuf);
+			      retval = GLOB_NOSPACE;
+			      goto out;
+			    }
+			  pwtmpbuf = newp;
+			  pwbuflen = 2 * pwbuflen;
+			  malloc_pwtmpbuf = 1;
+			}
 		      __set_errno (save);
 		    }
 #   else
 		  p = getpwnam (name);
 #   endif
 		  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 (__builtin_expect (malloc_home_dir, 0))
+		    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 (__builtin_expect (malloc_dirname, 0))
+		free (dirname);
+
 	      dirname = home_dir;
 	      dirlen = strlen (dirname);
+	      malloc_dirname = malloc_home_dir;
 	    }
 	  else
 	    {
 	      char *newp;
 	      size_t home_len = strlen (home_dir);
-	      newp = (char *) __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 (__builtin_expect (malloc_home_dir, 0))
+			free (home_dir);
+		      retval = GLOB_NOSPACE;
+		      goto out;
+		    }
+		}
+
 	      mempcpy (mempcpy (newp, home_dir, home_len),
 		       &dirname[1], dirlen);
+
+	      if (__builtin_expect (malloc_dirname, 0))
+		free (dirname);
+
 	      dirname = newp;
 	      dirlen += home_len - 1;
+	      malloc_dirname = !use_alloca;
 	    }
 	  dirname_modified = 1;
 	}
@@ -657,7 +760,8 @@ glob (pattern, flags, errfunc, pglob)
       else
 	{
 	  char *end_name = strchr (dirname, '/');
-	  const char *user_name;
+	  char *user_name;
+	  int malloc_user_name = 0;
 	  const char *home_dir;
 	  char *unescape = NULL;
 
@@ -677,7 +781,18 @@ glob (pattern, flags, errfunc, pglob)
 	  else
 	    {
 	      char *newp;
-	      newp = (char *) __alloca (end_name - dirname);
+	      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,
@@ -714,6 +829,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;
 
@@ -723,7 +839,21 @@ glob (pattern, flags, errfunc, pglob)
 		 moderate value.  */
 	      buflen = 1024;
 #   endif
-	    pwtmpbuf = (char *) __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 (__builtin_expect (malloc_user_name, 0))
+		      free (user_name);
+		    retval = GLOB_NOSPACE;
+		    goto out;
+		  }
+		malloc_pwtmpbuf = 1;
+	      }
 
 	    while (getpwnam_r (user_name, &pwbuf, pwtmpbuf, buflen, &p) != 0)
 	      {
@@ -732,40 +862,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 (__builtin_expect (malloc_pwtmpbuf, 0))
+			  free (pwtmpbuf);
+			goto nomem_getpw;
+		      }
+		    pwtmpbuf = newp;
+		    malloc_pwtmpbuf = 1;
+		  }
 		__set_errno (save);
 	      }
 #  else
 	    p = getpwnam (user_name);
 #  endif
+
+	    if (__builtin_expect (malloc_user_name, 0))
+	      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 (__builtin_expect (malloc_dirname, 0))
+		  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 (__builtin_expect (malloc_pwtmpbuf, 0))
+			  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 (__builtin_expect (malloc_pwtmpbuf, 0))
+		  free (pwtmpbuf);
+	      }
 	    else
-	      home_dir = NULL;
+	      {
+		if (__builtin_expect (malloc_pwtmpbuf, 0))
+		  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 = (char *) __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.  */
     }
@@ -899,7 +1066,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;
@@ -1000,7 +1167,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
@@ -1063,7 +1231,11 @@ glob (pattern, flags, errfunc, pglob)
 	     sizeof (char *), collated_compare);
     }
 
-  return 0;
+ out:
+  if (__builtin_expect (malloc_dirname, 0))
+    free (dirname);
+
+  return retval;
 }
 #if defined _LIBC && !defined glob
 libc_hidden_def (glob)
@@ -1273,7 +1445,7 @@ link_exists2_p (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;
@@ -1288,11 +1460,12 @@ 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;
 
+  alloca_used += sizeof (init_names);
+
   init_names.next = NULL;
   init_names.count = INITIAL_COUNT;
 
@@ -1308,20 +1481,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 = (char *) __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 (__builtin_expect (!alloca_fullname, 0))
+	free (fullname);
     }
   else
     {
@@ -1409,9 +1598,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;