Add a few more alloca size checks

This commit is contained in:
Ulrich Drepper 2011-05-22 23:04:16 -04:00
parent de7ce8f171
commit f2962a7195
5 changed files with 373 additions and 114 deletions

View File

@ -1,5 +1,13 @@
2011-05-22 Ulrich Drepper <drepper@gmail.com> 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 * elf/dl-runtime.c (_dl_profile_fixup): Also store LA_SYMB_NOPLTENTER
and LA_SYMB_NOPLTEXIT in flags which are passed to pltenter and and LA_SYMB_NOPLTEXIT in flags which are passed to pltenter and
pltexit. pltexit.

8
NEWS
View File

@ -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. Copyright (C) 1992-2009, 2010, 2011 Free Software Foundation, Inc.
See the end for copying conditions. See the end for copying conditions.
@ -15,9 +15,9 @@ Version 2.14
12158, 12178, 12200, 12346, 12393, 12420, 12432, 12445, 12449, 12453, 12158, 12178, 12200, 12346, 12393, 12420, 12432, 12445, 12449, 12453,
12454, 12460, 12469, 12489, 12509, 12510, 12511, 12518, 12527, 12541, 12454, 12460, 12469, 12489, 12509, 12510, 12511, 12518, 12527, 12541,
12545, 12551, 12582, 12583, 12587, 12597, 12601, 12611, 12625, 12626, 12545, 12551, 12582, 12583, 12587, 12597, 12601, 12611, 12625, 12626,
12631, 12650, 12653, 12655, 12660, 12681, 12685, 12711, 12713, 12714, 12631, 12650, 12653, 12655, 12660, 12671, 12681, 12685, 12711, 12713,
12717, 12723, 12724, 12734, 12738, 12746, 12766, 12775, 12777, 12782, 12714, 12717, 12723, 12724, 12734, 12738, 12746, 12766, 12775, 12777,
12788, 12792 12782, 12788, 12792
* The RPC implementation in libc is obsoleted. Old programs keep working * The RPC implementation in libc is obsoleted. Old programs keep working
but new programs cannot be linked with the routines in libc anymore. but new programs cannot be linked with the routines in libc anymore.

View File

@ -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. This file is part of the GNU C Library.
Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996. 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; int yperr;
if (new_start) if (new_start)
yperr = yp_first (domain, "mail.aliases", &outkey, &keylen, &result, yperr = yp_first (domain, "mail.aliases", &outkey, &keylen, &result,
&len); &len);
else else
yperr = yp_next (domain, "mail.aliases", oldkey, oldkeylen, &outkey, yperr = yp_next (domain, "mail.aliases", oldkey, oldkeylen, &outkey,
&keylen, &result, &len); &keylen, &result, &len);
if (__builtin_expect (yperr != YPERR_SUCCESS, 0)) 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); enum nss_status retval = yperr2nss (yperr);
if (retval == NSS_STATUS_TRYAGAIN) if (retval == NSS_STATUS_TRYAGAIN)
*errnop = errno; *errnop = errno;
return retval; return retval;
} }
if (__builtin_expect ((size_t) (len + 1) > buflen, 0)) if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
{ {
free (result); free (result);
*errnop = ERANGE; *errnop = ERANGE;
return NSS_STATUS_TRYAGAIN; return NSS_STATUS_TRYAGAIN;
} }
char *p = strncpy (buffer, result, len); char *p = strncpy (buffer, result, len);
buffer[len] = '\0'; buffer[len] = '\0';
while (isspace (*p)) while (isspace (*p))
++p; ++p;
free (result); free (result);
parse_res = _nss_nis_parse_aliasent (outkey, p, alias, buffer, 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; return NSS_STATUS_UNAVAIL;
} }
size_t namlen = strlen (name);
char name2[namlen + 1];
char *domain; char *domain;
if (__builtin_expect (yp_get_default_domain (&domain), 0)) if (__builtin_expect (yp_get_default_domain (&domain), 0))
return NSS_STATUS_UNAVAIL; 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. */ /* Convert name to lowercase. */
size_t i; size_t i;
for (i = 0; i < namlen; ++i) for (i = 0; i < namlen; ++i)
@ -230,6 +242,9 @@ _nss_nis_getaliasbyname_r (const char *name, struct aliasent *alias,
int len; int len;
int yperr = yp_match (domain, "mail.aliases", name2, namlen, &result, &len); int yperr = yp_match (domain, "mail.aliases", name2, namlen, &result, &len);
if (!use_alloca)
free (name2);
if (__builtin_expect (yperr != YPERR_SUCCESS, 0)) if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
{ {
enum nss_status retval = yperr2nss (yperr); enum nss_status retval = yperr2nss (yperr);

View File

@ -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. This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2007. Contributed by Ulrich Drepper <drepper@redhat.com>, 2007.
@ -17,6 +17,7 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */ 02111-1307 USA. */
#include <assert.h>
#include <errno.h> #include <errno.h>
#include <string.h> #include <string.h>
#include <not-cancel.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 gc_cycle;
int nretries = 0; int nretries = 0;
size_t alloca_used = 0;
/* If the mapping is available, try to search there instead of /* If the mapping is available, try to search there instead of
communicating with the nscd. */ communicating with the nscd. */
@ -88,13 +90,23 @@ nscd_getserv_r (const char *crit, size_t critlen, const char *proto,
&gc_cycle); &gc_cycle);
size_t protolen = proto == NULL ? 0 : strlen (proto); size_t protolen = proto == NULL ? 0 : strlen (proto);
size_t keylen = critlen + 1 + protolen + 1; 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), memcpy (__mempcpy (__mempcpy (key, crit, critlen),
"/", 1), proto ?: "", protolen + 1); "/", 1), proto ?: "", protolen + 1);
retry:; retry:;
const char *s_name = NULL; const char *s_name = NULL;
const char *s_proto = NULL; const char *s_proto = NULL;
int alloca_aliases_len = 0;
const uint32_t *aliases_len = NULL; const uint32_t *aliases_len = NULL;
const char *aliases_list = NULL; const char *aliases_list = NULL;
int retval = -1; 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)) if (((uintptr_t) aliases_len & (__alignof__ (*aliases_len) - 1))
!= 0) != 0)
{ {
uint32_t *tmp = alloca (serv_resp.s_aliases_cnt uint32_t *tmp;
* sizeof (uint32_t)); 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, aliases_len = memcpy (tmp, aliases_len,
serv_resp.s_aliases_cnt serv_resp.s_aliases_cnt
* sizeof (uint32_t)); * 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) if (serv_resp.s_aliases_cnt > 0)
{ {
aliases_len = alloca (serv_resp.s_aliases_cnt assert (alloca_aliases_len == 0);
* sizeof (uint32_t)); 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_base = (void *) aliases_len;
vec[n].iov_len = serv_resp.s_aliases_cnt * sizeof (uint32_t); 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; goto retry;
} }
if (!alloca_aliases_len)
free ((void *) aliases_len);
if (!alloca_key)
free (key);
return retval; return retval;
} }

View File

@ -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. Free Software Foundation, Inc.
This file is part of the GNU C Library. 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, static int glob_in_dir (const char *pattern, const char *directory,
int flags, int (*errfunc) (const char *, int), 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) extern int __glob_pattern_type (const char *pattern, int quote)
attribute_hidden; attribute_hidden;
@ -253,13 +253,18 @@ glob (pattern, flags, errfunc, pglob)
glob_t *pglob; glob_t *pglob;
{ {
const char *filename; const char *filename;
const char *dirname; char *dirname = NULL;
size_t dirlen; size_t dirlen;
int status; int status;
size_t oldcount; size_t oldcount;
int meta; int meta;
int dirname_modified; int dirname_modified;
int malloc_dirname = 0;
glob_t dirs; glob_t dirs;
int retval = 0;
#ifdef _LIBC
size_t alloca_used = 0;
#endif
if (pattern == NULL || pglob == NULL || (flags & ~__GLOB_FLAGS) != 0) if (pattern == NULL || pglob == NULL || (flags & ~__GLOB_FLAGS) != 0)
{ {
@ -308,20 +313,26 @@ glob (pattern, flags, errfunc, pglob)
const char *next; const char *next;
const char *rest; const char *rest;
size_t rest_len; size_t rest_len;
#ifdef __GNUC__ char *onealt;
char onealt[strlen (pattern) - 1]; size_t pattern_len = strlen (pattern) - 1;
#else #ifdef _LIBC
char *onealt = (char *) malloc (strlen (pattern) - 1); int alloca_onealt = __libc_use_alloca (alloca_used + pattern_len);
if (onealt == NULL) if (alloca_onealt)
{ onealt = alloca_account (pattern_len, alloca_used);
if (!(flags & GLOB_APPEND)) else
{
pglob->gl_pathc = 0;
pglob->gl_pathv = NULL;
}
return GLOB_NOSPACE;
}
#endif #endif
{
onealt = (char *) malloc (pattern_len);
if (onealt == NULL)
{
if (!(flags & GLOB_APPEND))
{
pglob->gl_pathc = 0;
pglob->gl_pathv = NULL;
}
return GLOB_NOSPACE;
}
}
/* We know the prefix for all sub-patterns. */ /* We know the prefix for all sub-patterns. */
alt_start = mempcpy (onealt, pattern, begin - pattern); alt_start = mempcpy (onealt, pattern, begin - pattern);
@ -332,9 +343,11 @@ glob (pattern, flags, errfunc, pglob)
if (next == NULL) if (next == NULL)
{ {
/* It is an illegal expression. */ /* It is an illegal expression. */
#ifndef __GNUC__ illegal_brace:
free (onealt); #ifdef _LIBC
if (__builtin_expect (!alloca_onealt, 0))
#endif #endif
free (onealt);
return glob (pattern, flags & ~GLOB_BRACE, errfunc, pglob); return glob (pattern, flags & ~GLOB_BRACE, errfunc, pglob);
} }
@ -344,13 +357,8 @@ glob (pattern, flags, errfunc, pglob)
{ {
rest = next_brace_sub (rest + 1, flags); rest = next_brace_sub (rest + 1, flags);
if (rest == NULL) if (rest == NULL)
{ /* It is an illegal expression. */
/* It is an illegal expression. */ goto illegal_brace;
#ifndef __GNUC__
free (onealt);
#endif
return glob (pattern, flags & ~GLOB_BRACE, errfunc, pglob);
}
} }
/* Please note that we now can be sure the brace expression /* Please note that we now can be sure the brace expression
is well-formed. */ is well-formed. */
@ -386,9 +394,10 @@ glob (pattern, flags, errfunc, pglob)
/* If we got an error, return it. */ /* If we got an error, return it. */
if (result && result != GLOB_NOMATCH) if (result && result != GLOB_NOMATCH)
{ {
#ifndef __GNUC__ #ifdef _LIBC
free (onealt); if (__builtin_expect (!alloca_onealt, 0))
#endif #endif
free (onealt);
if (!(flags & GLOB_APPEND)) if (!(flags & GLOB_APPEND))
{ {
globfree (pglob); globfree (pglob);
@ -406,9 +415,10 @@ glob (pattern, flags, errfunc, pglob)
assert (next != NULL); assert (next != NULL);
} }
#ifndef __GNUC__ #ifdef _LIBC
free (onealt); if (__builtin_expect (!alloca_onealt, 0))
#endif #endif
free (onealt);
if (pglob->gl_pathc != firstc) if (pglob->gl_pathc != firstc)
/* We found some entries. */ /* We found some entries. */
@ -455,7 +465,7 @@ glob (pattern, flags, errfunc, pglob)
case is nothing but a notation for a directory. */ case is nothing but a notation for a directory. */
if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && pattern[0] == '~') if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && pattern[0] == '~')
{ {
dirname = pattern; dirname = (char *) pattern;
dirlen = strlen (pattern); dirlen = strlen (pattern);
/* Set FILENAME to NULL as a special flag. This is ugly but /* Set FILENAME to NULL as a special flag. This is ugly but
@ -473,9 +483,9 @@ glob (pattern, flags, errfunc, pglob)
filename = pattern; filename = pattern;
#ifdef _AMIGA #ifdef _AMIGA
dirname = ""; dirname = (char *) "";
#else #else
dirname = "."; dirname = (char *) ".";
#endif #endif
dirlen = 0; dirlen = 0;
} }
@ -485,7 +495,7 @@ glob (pattern, flags, errfunc, pglob)
&& (flags & GLOB_NOESCAPE) == 0)) && (flags & GLOB_NOESCAPE) == 0))
{ {
/* "/pattern" or "\\/pattern". */ /* "/pattern" or "\\/pattern". */
dirname = "/"; dirname = (char *) "/";
dirlen = 1; dirlen = 1;
++filename; ++filename;
} }
@ -511,7 +521,17 @@ glob (pattern, flags, errfunc, pglob)
from "d:/", since "d:" and "d:/" are not the same.*/ from "d:/", since "d:" and "d:/" are not the same.*/
} }
#endif #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'; *((char *) mempcpy (newp, pattern, dirlen)) = '\0';
dirname = newp; dirname = newp;
++filename; ++filename;
@ -551,7 +571,8 @@ glob (pattern, flags, errfunc, pglob)
oldcount = pglob->gl_pathc + pglob->gl_offs; oldcount = pglob->gl_pathc + pglob->gl_offs;
goto no_matches; goto no_matches;
} }
return val; retval = val;
goto out;
} }
} }
@ -563,7 +584,8 @@ glob (pattern, flags, errfunc, pglob)
&& (dirname[2] == '\0' || dirname[2] == '/'))) && (dirname[2] == '\0' || dirname[2] == '/')))
{ {
/* Look up home directory. */ /* Look up home directory. */
const char *home_dir = getenv ("HOME"); char *home_dir = getenv ("HOME");
int malloc_home_dir = 0;
# ifdef _AMIGA # ifdef _AMIGA
if (home_dir == NULL || home_dir[0] == '\0') if (home_dir == NULL || home_dir[0] == '\0')
home_dir = "SYS:"; home_dir = "SYS:";
@ -582,7 +604,7 @@ glob (pattern, flags, errfunc, pglob)
/* `sysconf' does not support _SC_LOGIN_NAME_MAX. Try /* `sysconf' does not support _SC_LOGIN_NAME_MAX. Try
a moderate value. */ a moderate value. */
buflen = 20; buflen = 20;
name = (char *) __alloca (buflen); name = alloca_account (buflen, alloca_used);
success = getlogin_r (name, buflen) == 0; success = getlogin_r (name, buflen) == 0;
if (success) if (success)
@ -592,6 +614,7 @@ glob (pattern, flags, errfunc, pglob)
long int pwbuflen = GETPW_R_SIZE_MAX (); long int pwbuflen = GETPW_R_SIZE_MAX ();
char *pwtmpbuf; char *pwtmpbuf;
struct passwd pwbuf; struct passwd pwbuf;
int malloc_pwtmpbuf = 0;
int save = errno; int save = errno;
# ifndef _LIBC # ifndef _LIBC
@ -600,7 +623,18 @@ glob (pattern, flags, errfunc, pglob)
Try a moderate value. */ Try a moderate value. */
pwbuflen = 1024; pwbuflen = 1024;
# endif # 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) while (getpwnam_r (name, &pwbuf, pwtmpbuf, pwbuflen, &p)
!= 0) != 0)
@ -610,46 +644,115 @@ glob (pattern, flags, errfunc, pglob)
p = NULL; p = NULL;
break; 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); 2 * pwbuflen);
# else if (newp == NULL)
pwbuflen *= 2; {
pwtmpbuf = (char *) __alloca (pwbuflen); if (__builtin_expect (malloc_pwtmpbuf, 0))
# endif free (pwtmpbuf);
retval = GLOB_NOSPACE;
goto out;
}
pwtmpbuf = newp;
pwbuflen = 2 * pwbuflen;
malloc_pwtmpbuf = 1;
}
__set_errno (save); __set_errno (save);
} }
# else # else
p = getpwnam (name); p = getpwnam (name);
# endif # endif
if (p != NULL) 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 (home_dir == NULL || home_dir[0] == '\0')
{ {
if (flags & GLOB_TILDE_CHECK) if (flags & GLOB_TILDE_CHECK)
return GLOB_NOMATCH; {
if (__builtin_expect (malloc_home_dir, 0))
free (home_dir);
retval = GLOB_NOMATCH;
goto out;
}
else else
home_dir = "~"; /* No luck. */ home_dir = (char *) "~"; /* No luck. */
} }
# endif /* WINDOWS32 */ # endif /* WINDOWS32 */
# endif # endif
/* Now construct the full directory. */ /* Now construct the full directory. */
if (dirname[1] == '\0') if (dirname[1] == '\0')
{ {
if (__builtin_expect (malloc_dirname, 0))
free (dirname);
dirname = home_dir; dirname = home_dir;
dirlen = strlen (dirname); dirlen = strlen (dirname);
malloc_dirname = malloc_home_dir;
} }
else else
{ {
char *newp; char *newp;
size_t home_len = strlen (home_dir); 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), mempcpy (mempcpy (newp, home_dir, home_len),
&dirname[1], dirlen); &dirname[1], dirlen);
if (__builtin_expect (malloc_dirname, 0))
free (dirname);
dirname = newp; dirname = newp;
dirlen += home_len - 1; dirlen += home_len - 1;
malloc_dirname = !use_alloca;
} }
dirname_modified = 1; dirname_modified = 1;
} }
@ -657,7 +760,8 @@ glob (pattern, flags, errfunc, pglob)
else else
{ {
char *end_name = strchr (dirname, '/'); char *end_name = strchr (dirname, '/');
const char *user_name; char *user_name;
int malloc_user_name = 0;
const char *home_dir; const char *home_dir;
char *unescape = NULL; char *unescape = NULL;
@ -677,7 +781,18 @@ glob (pattern, flags, errfunc, pglob)
else else
{ {
char *newp; 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) if (unescape != NULL)
{ {
char *p = mempcpy (newp, dirname + 1, char *p = mempcpy (newp, dirname + 1,
@ -714,6 +829,7 @@ glob (pattern, flags, errfunc, pglob)
# if defined HAVE_GETPWNAM_R || defined _LIBC # if defined HAVE_GETPWNAM_R || defined _LIBC
long int buflen = GETPW_R_SIZE_MAX (); long int buflen = GETPW_R_SIZE_MAX ();
char *pwtmpbuf; char *pwtmpbuf;
int malloc_pwtmpbuf = 0;
struct passwd pwbuf; struct passwd pwbuf;
int save = errno; int save = errno;
@ -723,7 +839,21 @@ glob (pattern, flags, errfunc, pglob)
moderate value. */ moderate value. */
buflen = 1024; buflen = 1024;
# endif # 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) while (getpwnam_r (user_name, &pwbuf, pwtmpbuf, buflen, &p) != 0)
{ {
@ -732,40 +862,77 @@ glob (pattern, flags, errfunc, pglob)
p = NULL; p = NULL;
break; break;
} }
# ifdef _LIBC if (!malloc_pwtmpbuf
pwtmpbuf = extend_alloca (pwtmpbuf, buflen, 2 * buflen); && __libc_use_alloca (alloca_used + 2 * buflen))
# else pwtmpbuf = extend_alloca_account (pwtmpbuf, buflen,
buflen *= 2; 2 * buflen, alloca_used);
pwtmpbuf = __alloca (buflen); else
# endif {
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); __set_errno (save);
} }
# else # else
p = getpwnam (user_name); p = getpwnam (user_name);
# endif # endif
if (__builtin_expect (malloc_user_name, 0))
free (user_name);
/* If we found a home directory use this. */
if (p != NULL) 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 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. */ # endif /* Not Amiga && not WINDOWS32. */
} }
@ -899,7 +1066,7 @@ glob (pattern, flags, errfunc, pglob)
status = glob_in_dir (filename, dirs.gl_pathv[i], status = glob_in_dir (filename, dirs.gl_pathv[i],
((flags | GLOB_APPEND) ((flags | GLOB_APPEND)
& ~(GLOB_NOCHECK | GLOB_NOMAGIC)), & ~(GLOB_NOCHECK | GLOB_NOMAGIC)),
errfunc, pglob); errfunc, pglob, alloca_used);
if (status == GLOB_NOMATCH) if (status == GLOB_NOMATCH)
/* No matches in this directory. Try the next. */ /* No matches in this directory. Try the next. */
continue; continue;
@ -1000,7 +1167,8 @@ glob (pattern, flags, errfunc, pglob)
} }
if (dirname_modified) if (dirname_modified)
flags &= ~(GLOB_NOCHECK | GLOB_NOMAGIC); 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 != 0)
{ {
if (status == GLOB_NOMATCH && flags != orig_flags if (status == GLOB_NOMATCH && flags != orig_flags
@ -1063,7 +1231,11 @@ glob (pattern, flags, errfunc, pglob)
sizeof (char *), collated_compare); sizeof (char *), collated_compare);
} }
return 0; out:
if (__builtin_expect (malloc_dirname, 0))
free (dirname);
return retval;
} }
#if defined _LIBC && !defined glob #if defined _LIBC && !defined glob
libc_hidden_def (glob) libc_hidden_def (glob)
@ -1273,7 +1445,7 @@ link_exists2_p (const char *dir, size_t dirlen, const char *fname,
static int static int
glob_in_dir (const char *pattern, const char *directory, int flags, glob_in_dir (const char *pattern, const char *directory, int flags,
int (*errfunc) (const char *, int), int (*errfunc) (const char *, int),
glob_t *pglob) glob_t *pglob, size_t alloca_used)
{ {
size_t dirlen = strlen (directory); size_t dirlen = strlen (directory);
void *stream = NULL; 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 = &init_names;
struct globnames *names_alloca = &init_names; struct globnames *names_alloca = &init_names;
size_t nfound = 0; size_t nfound = 0;
size_t allocasize = sizeof (init_names);
size_t cur = 0; size_t cur = 0;
int meta; int meta;
int save; int save;
alloca_used += sizeof (init_names);
init_names.next = NULL; init_names.next = NULL;
init_names.count = INITIAL_COUNT; 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() /* Since we use the normal file functions we can also use stat()
to verify the file is there. */ to verify the file is there. */
struct stat st; union
struct_stat64 st64; {
struct stat st;
struct_stat64 st64;
} ust;
size_t patlen = strlen (pattern); 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), mempcpy (mempcpy (mempcpy (fullname, directory, dirlen),
"/", 1), "/", 1),
pattern, patlen + 1); pattern, patlen + 1);
if ((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0) if ((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)
? (*pglob->gl_stat) (fullname, &st) ? (*pglob->gl_stat) (fullname, &ust.st)
: __stat64 (fullname, &st64)) == 0) : __stat64 (fullname, &ust.st64)) == 0)
/* We found this file to be existing. Now tell the rest /* We found this file to be existing. Now tell the rest
of the function to copy this name into the result. */ of the function to copy this name into the result. */
flags |= GLOB_NOCHECK; flags |= GLOB_NOCHECK;
if (__builtin_expect (!alloca_fullname, 0))
free (fullname);
} }
else else
{ {
@ -1409,9 +1598,9 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
size_t size = (sizeof (struct globnames) size_t size = (sizeof (struct globnames)
+ ((count - INITIAL_COUNT) + ((count - INITIAL_COUNT)
* sizeof (char *))); * sizeof (char *)));
allocasize += size; if (__libc_use_alloca (alloca_used + size))
if (__libc_use_alloca (allocasize)) newnames = names_alloca
newnames = names_alloca = __alloca (size); = alloca_account (size, alloca_used);
else if ((newnames = malloc (size)) else if ((newnames = malloc (size))
== NULL) == NULL)
goto memory_error; goto memory_error;