This is the mail archive of the glibc-cvs@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

GNU C Library master sources branch fw/extend_alloca created. glibc-2.23-247-ga23008e


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU C Library master sources".

The branch, fw/extend_alloca has been created
        at  a23008e93eaeeff0059e96ebfc81e23ca56d5bcf (commit)

- Log -----------------------------------------------------------------
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=a23008e93eaeeff0059e96ebfc81e23ca56d5bcf

commit a23008e93eaeeff0059e96ebfc81e23ca56d5bcf
Author: Florian Weimer <fweimer@redhat.com>
Date:   Sun Mar 1 23:22:45 2015 +0100

    Remove macros extend_alloca, extend_alloca_account [BZ #18023]
    
    And also the helper macro stackinfo_alloca_round.
    
    extend_alloca simply does not work on x86_64 and current i386 because
    its peculiar stack alignment rules.
    
    Here's an analysis of the _dl_fini situation (before the removal of
    extend_alloca).
    
    Dump of assembler code for function _dl_fini:
    <+0>:	push   %rbp
    <+1>:	mov    %rsp,%rbp
    <+4>:	push   %r15
    <+6>:	push   %r14
    <+8>:	push   %r13
    <+10>:	push   %r12
    <+12>:	push   %rbx
    <+13>:	sub    $0x38,%rsp
    
    The function pushes 6 registers on the stack and allocates 0x38 bytes,
    which means that %rsp is a multiple of 16 after function prologue.
    
    The initial alloca allocation does not change %rsp alignment:
    
    <+210>:	shr    $0x4,%rcx
    <+214>:	shl    $0x4,%rcx
    <+218>:	sub    %rcx,%rsp
    
    %r15 is the address of the previous stack allocation, it is used below.
    
    This is the extend_alloca reallocation branch:
    
    <+734>:	add    $0xf,%rdx
    <+738>:	and    $0xfffffffffffffff0,%rdx
    <+742>:	lea    0x1e(%rdx),%rcx
    <+746>:	shr    $0x4,%rcx
    <+750>:	shl    $0x4,%rcx
    <+754>:	sub    %rcx,%rsp
    <+757>:	lea    0xf(%rsp),%rcx
    <+762>:	and    $0xfffffffffffffff0,%rcx
    <+766>:	lea    (%rcx,%rdx,1),%rsi
    <+770>:	cmp    %rsi,%r15
    <+773>:	je     0x7f963940b673 <_dl_fini+787>
    <+775>:	mov    %rdx,-0x58(%rbp)
    <+787>:	add    %rdx,-0x58(%rbp)
    
    (a) %rdx, the new requested size, is rounded up to a multiple of 16
    (+734, %+738), and the result is stored in %rdx@738.
    
    (b) %rdx@738 + 31 is rounded down to a multiple of 16, the result is
    stored in rcx@750 (+742, +746, +750).  So %rcx@750 == %rdx@738 + 16.
    
    (c) %rcx@750 bytes are allocated on the stack (+754).  %rsp is rounded
    upwards to a multiple of 16, result is stored in %rcx@762 (+757, +762).
    This does not change the value of %rsp because it already was a multiple
    of 16.
    
    (d) %rsi@766 == %rcx@762 + %rdx@738 is compared against %r15.  But this
    comparison is always false because we allocated 16 extra bytes on the
    stack in (b), which were reserved for the alignment in (c), but in fact
    unused.  We are left with a gap in stack usage, and the comparison is
    always false.
    
    (@XXX refers to register values after executing the instruction at
    offset +XXX.)
    
    If the alignment gap was actually used because of different alignment
    for %rsp, then the comparison failure would still occur because the gap
    would not have been added after this reallocation, but before the
    previous allocation.
    
    As a result, extend_alloca is never able to merge allocations.  It also
    turns out that the interface is difficult to use, especially in
    cojunction with alloca account (which is rarely optional).
    
    	[BZ #18023]
    	* include/alloca.h (stackinfo_alloca_round, extend_alloca,
    	extend_alloca_account): Remove.

diff --git a/include/alloca.h b/include/alloca.h
index 0150025..f190b87 100644
--- a/include/alloca.h
+++ b/include/alloca.h
@@ -20,57 +20,17 @@ libc_hidden_proto (__libc_alloca_cutoff)
 
 #include <allocalim.h>
 
-#ifndef stackinfo_alloca_round
-# define stackinfo_alloca_round(l) (((l) + 15) & -16)
-#endif
-
-#if _STACK_GROWS_DOWN
-# define extend_alloca(buf, len, newlen) \
-  (__typeof (buf)) ({ size_t __newlen = stackinfo_alloca_round (newlen);      \
-		      char *__newbuf = __alloca (__newlen);		      \
-		      if (__newbuf + __newlen == (char *) (buf))	      \
-			len += __newlen;				      \
-		      else						      \
-			len = __newlen;					      \
-		      __newbuf; })
-#elif _STACK_GROWS_UP
-# define extend_alloca(buf, len, newlen) \
-  (__typeof (buf)) ({ size_t __newlen = stackinfo_alloca_round (newlen);      \
-		      char *__newbuf = __alloca (__newlen);		      \
-		      char *__buf = (char *) (buf);			      \
-		      if (__buf + len == __newbuf)			      \
-			{						      \
-			  len += __newlen;				      \
-			  __newbuf = __buf;				      \
-			}						      \
-		      else						      \
-			len = __newlen;					      \
-		      __newbuf; })
-#else
-# define extend_alloca(buf, len, newlen) \
-  __alloca (((len) = (newlen)))
-#endif
-
 #if defined stackinfo_get_sp && defined stackinfo_sub_sp
 # define alloca_account(size, avar) \
   ({ void *old__ = stackinfo_get_sp ();					      \
      void *m__ = __alloca (size);					      \
      avar += stackinfo_sub_sp (old__);					      \
      m__; })
-# define extend_alloca_account(buf, len, newlen, avar) \
-  ({ void *old__ = stackinfo_get_sp ();					      \
-     void *m__ = extend_alloca (buf, len, newlen);			      \
-     avar += stackinfo_sub_sp (old__);					      \
-     m__; })
 #else
 # define alloca_account(size, avar) \
   ({ size_t s__ = (size);						      \
      avar += s__;							      \
      __alloca (s__); })
-# define extend_alloca_account(buf, len, newlen, avar) \
-  ({ size_t s__ = (newlen);						      \
-     avar += s__;							      \
-     extend_alloca (buf, len, s__); })
 #endif
 
 #endif

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=5460234530592ea0fca633600c0ed02f3286e7cb

commit 5460234530592ea0fca633600c0ed02f3286e7cb
Author: Florian Weimer <fweimer@redhat.com>
Date:   Sun Mar 1 19:49:50 2015 +0100

    glob: Rewrite to use struct scratch_buffer instead of extend_alloca
    
    	[BZ #18023]
    	* posix/glob.c (glob): Use struct scratch_buffer instead of
    	extend_alloca.

diff --git a/posix/glob.c b/posix/glob.c
index 0c04c3c..0914eec 100644
--- a/posix/glob.c
+++ b/posix/glob.c
@@ -25,6 +25,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <stddef.h>
+#include <scratch_buffer.h>
 
 /* Outcomment the following line for production quality code.  */
 /* #define NDEBUG 1 */
@@ -264,7 +265,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
   glob_t dirs;
   int retval = 0;
 #ifdef _LIBC
-  size_t alloca_used = 0;
+  size_t alloca_used = sizeof (struct scratch_buffer);
 #endif
 
   if (pattern == NULL || pglob == NULL || (flags & ~__GLOB_FLAGS) != 0)
@@ -621,33 +622,13 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
 		{
 		  struct passwd *p;
 #   if defined HAVE_GETPWNAM_R || defined _LIBC
-		  long int pwbuflen = GETPW_R_SIZE_MAX ();
-		  char *pwtmpbuf;
 		  struct passwd pwbuf;
-		  int malloc_pwtmpbuf = 0;
 		  int save = errno;
+		  struct scratch_buffer pwtmpbuf;
+		  scratch_buffer_init (&pwtmpbuf);
 
-#    ifndef _LIBC
-		  if (pwbuflen == -1)
-		    /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX.
-		       Try a moderate value.  */
-		    pwbuflen = 1024;
-#    endif
-		  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)
+		  while (getpwnam_r (name, &pwbuf,
+				     pwtmpbuf.data, pwtmpbuf.length, &p) != 0)
 		    {
 		      if (errno != ERANGE)
 			{
@@ -655,67 +636,37 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
 			  break;
 			}
 
-		      if (!malloc_pwtmpbuf
-			  && __libc_use_alloca (alloca_used
-						+ 2 * pwbuflen))
-			pwtmpbuf = extend_alloca_account (pwtmpbuf, pwbuflen,
-							  2 * pwbuflen,
-							  alloca_used);
-		      else
+		      if (!scratch_buffer_grow (&pwtmpbuf))
 			{
-			  char *newp = realloc (malloc_pwtmpbuf
-						? pwtmpbuf : NULL,
-						2 * pwbuflen);
-			  if (newp == NULL)
-			    {
-			      if (__glibc_unlikely (malloc_pwtmpbuf))
-				free (pwtmpbuf);
-			      retval = GLOB_NOSPACE;
-			      goto out;
-			    }
-			  pwtmpbuf = newp;
-			  pwbuflen = 2 * pwbuflen;
-			  malloc_pwtmpbuf = 1;
+			  retval = GLOB_NOSPACE;
+			  goto out;
 			}
 		      __set_errno (save);
 		    }
 #   else
-		  p = getpwnam (name);
+		  p = getpwnam (namebuf.data);
 #   endif
 		  if (p != NULL)
 		    {
-		      if (!malloc_pwtmpbuf)
-			home_dir = p->pw_dir;
-		      else
+		      home_dir = strdup (p->pw_dir);
+		      malloc_home_dir = 1;
+		      if (home_dir == NULL)
 			{
-			  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);
+			  scratch_buffer_free (&pwtmpbuf);
+			  retval = GLOB_NOSPACE;
+			  goto out;
 			}
 		    }
+		  scratch_buffer_free (&pwtmpbuf);
 		}
 	    }
 	  if (home_dir == NULL || home_dir[0] == '\0')
 	    {
+	      if (malloc_home_dir)
+		free (home_dir);
+	      malloc_home_dir = 0;
 	      if (flags & GLOB_TILDE_CHECK)
 		{
-		  if (__glibc_unlikely (malloc_home_dir))
-		    free (home_dir);
 		  retval = GLOB_NOMATCH;
 		  goto out;
 		}
@@ -836,57 +787,24 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
 	  {
 	    struct passwd *p;
 #  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;
+	    struct scratch_buffer pwtmpbuf;
+	    scratch_buffer_init (&pwtmpbuf);
 
-#   ifndef _LIBC
-	    if (buflen == -1)
-	      /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX.  Try a
-		 moderate value.  */
-	      buflen = 1024;
-#   endif
-	    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)
+	    while (getpwnam_r (user_name, &pwbuf,
+			       pwtmpbuf.data, pwtmpbuf.length, &p) != 0)
 	      {
 		if (errno != ERANGE)
 		  {
 		    p = NULL;
 		    break;
 		  }
-		if (!malloc_pwtmpbuf
-		    && __libc_use_alloca (alloca_used + 2 * buflen))
-		  pwtmpbuf = extend_alloca_account (pwtmpbuf, buflen,
-						    2 * buflen, alloca_used);
-		else
+
+		if (!scratch_buffer_grow (&pwtmpbuf))
 		  {
-		    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;
+		    retval = GLOB_NOSPACE;
+		    goto out;
 		  }
 		__set_errno (save);
 	      }
@@ -915,8 +833,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
 		    dirname = malloc (home_len + rest_len + 1);
 		    if (dirname == NULL)
 		      {
-			if (__glibc_unlikely (malloc_pwtmpbuf))
-			  free (pwtmpbuf);
+			scratch_buffer_free (&pwtmpbuf);
 			retval = GLOB_NOSPACE;
 			goto out;
 		      }
@@ -928,13 +845,11 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int),
 		dirlen = home_len + rest_len;
 		dirname_modified = 1;
 
-		if (__glibc_unlikely (malloc_pwtmpbuf))
-		  free (pwtmpbuf);
+		scratch_buffer_free (&pwtmpbuf);
 	      }
 	    else
 	      {
-		if (__glibc_unlikely (malloc_pwtmpbuf))
-		  free (pwtmpbuf);
+		scratch_buffer_free (&pwtmpbuf);
 
 		if (flags & GLOB_TILDE_CHECK)
 		  /* We have to regard it as an error if we cannot find the

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=c39657397cae6ca7f312967bac566b8f668c6973

commit c39657397cae6ca7f312967bac566b8f668c6973
Author: Florian Weimer <fweimer@redhat.com>
Date:   Sun Mar 1 19:48:31 2015 +0100

    wordexp: Rewrite parse_tilde to use struct scratch_buffer
    
    	[BZ #18023]
    	* posix/wordexp.c (parse_tilde): Use struct scratch_buffer
    	instead of extend_alloca.

diff --git a/posix/wordexp.c b/posix/wordexp.c
index ecc7615..1f5e7d9 100644
--- a/posix/wordexp.c
+++ b/posix/wordexp.c
@@ -17,7 +17,6 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <alloca.h>
 #include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -41,6 +40,7 @@
 #include <wchar.h>
 #include <wordexp.h>
 #include <kernel-features.h>
+#include <scratch_buffer.h>
 
 #include <libc-lock.h>
 #include <_itoa.h>
@@ -308,12 +308,7 @@ parse_tilde (char **word, size_t *word_length, size_t *max_length,
   if (i == 1 + *offset)
     {
       /* Tilde appears on its own */
-      uid_t uid;
-      struct passwd pwd, *tpwd;
-      int buflen = 1000;
       char* home;
-      char* buffer;
-      int result;
 
       /* POSIX.2 says ~ expands to $HOME and if HOME is unset the
 	 results are unspecified.  We do a lookup on the uid if
@@ -328,25 +323,38 @@ parse_tilde (char **word, size_t *word_length, size_t *max_length,
 	}
       else
 	{
-	  uid = __getuid ();
-	  buffer = __alloca (buflen);
-
-	  while ((result = __getpwuid_r (uid, &pwd, buffer, buflen, &tpwd)) != 0
+	  struct passwd pwd, *tpwd;
+	  uid_t uid = __getuid ();
+	  int result;
+	  struct scratch_buffer tmpbuf;
+	  scratch_buffer_init (&tmpbuf);
+
+	  while ((result = __getpwuid_r (uid, &pwd,
+					 tmpbuf.data, tmpbuf.length,
+					 &tpwd)) != 0
 		 && errno == ERANGE)
-	    buffer = extend_alloca (buffer, buflen, buflen + 1000);
+	    if (!scratch_buffer_grow (&tmpbuf))
+	      return WRDE_NOSPACE;
 
 	  if (result == 0 && tpwd != NULL && pwd.pw_dir != NULL)
 	    {
 	      *word = w_addstr (*word, word_length, max_length, pwd.pw_dir);
 	      if (*word == NULL)
-		return WRDE_NOSPACE;
+		{
+		  scratch_buffer_free (&tmpbuf);
+		  return WRDE_NOSPACE;
+		}
 	    }
 	  else
 	    {
 	      *word = w_addchar (*word, word_length, max_length, '~');
 	      if (*word == NULL)
-		return WRDE_NOSPACE;
+		{
+		  scratch_buffer_free (&tmpbuf);
+		  return WRDE_NOSPACE;
+		}
 	    }
+	  scratch_buffer_free (&tmpbuf);
 	}
     }
   else
@@ -354,13 +362,15 @@ parse_tilde (char **word, size_t *word_length, size_t *max_length,
       /* Look up user name in database to get home directory */
       char *user = strndupa (&words[1 + *offset], i - (1 + *offset));
       struct passwd pwd, *tpwd;
-      int buflen = 1000;
-      char* buffer = __alloca (buflen);
       int result;
+      struct scratch_buffer tmpbuf;
+      scratch_buffer_init (&tmpbuf);
 
-      while ((result = __getpwnam_r (user, &pwd, buffer, buflen, &tpwd)) != 0
+      while ((result = __getpwnam_r (user, &pwd, tmpbuf.data, tmpbuf.length,
+				     &tpwd)) != 0
 	     && errno == ERANGE)
-	buffer = extend_alloca (buffer, buflen, buflen + 1000);
+	if (!scratch_buffer_grow (&tmpbuf))
+	  return WRDE_NOSPACE;
 
       if (result == 0 && tpwd != NULL && pwd.pw_dir)
 	*word = w_addstr (*word, word_length, max_length, pwd.pw_dir);
@@ -372,6 +382,8 @@ parse_tilde (char **word, size_t *word_length, size_t *max_length,
 	    *word = w_addstr (*word, word_length, max_length, user);
 	}
 
+      scratch_buffer_free (&tmpbuf);
+
       *offset = i - 1;
     }
   return *word ? 0 : WRDE_NOSPACE;

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=4489ba51376e7bffaef6b3dd49e4049e81176b95

commit 4489ba51376e7bffaef6b3dd49e4049e81176b95
Author: Florian Weimer <fweimer@redhat.com>
Date:   Sun Mar 1 19:38:42 2015 +0100

    getaddrinfo: Use struct scratch_buffer instead of extend_alloca
    
    This results in slightly smaller buffers in some cases, but as the
    buffer size is passed to the called functions (and they will request
    an increased buffer size with an ERANGE error code), this does not
    result in a functional difference.
    
    	[BZ #18023]
    	* sysdeps/posix/getaddrinfo.c (gaih_inet_serv, gethosts)
    	(gaih_inet): Use struct scratch_buffer instead of extend_alloca.

diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 1ef3f20..6e70263 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -63,6 +63,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <nscd/nscd-client.h>
 #include <nscd/nscd_proto.h>
 #include <resolv/res_hconf.h>
+#include <scratch_buffer.h>
 
 #ifdef HAVE_LIBIDN
 extern int __idna_to_ascii_lz (const char *input, char **output, int flags);
@@ -138,23 +139,27 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
 		const struct addrinfo *req, struct gaih_servtuple *st)
 {
   struct servent *s;
-  size_t tmpbuflen = 1024;
   struct servent ts;
-  char *tmpbuf;
   int r;
+  struct scratch_buffer tmpbuf;
+  scratch_buffer_init (&tmpbuf);
 
   do
     {
-      tmpbuf = __alloca (tmpbuflen);
-
-      r = __getservbyname_r (servicename, tp->name, &ts, tmpbuf, tmpbuflen,
-			     &s);
+      r = __getservbyname_r (servicename, tp->name, &ts,
+			     tmpbuf.data, tmpbuf.length, &s);
       if (r != 0 || s == NULL)
 	{
 	  if (r == ERANGE)
-	    tmpbuflen *= 2;
+	    {
+	      if (!scratch_buffer_grow (&tmpbuf))
+		return -EAI_MEMORY;
+	    }
 	  else
-	    return -EAI_SERVICE;
+	    {
+	      scratch_buffer_free (&tmpbuf);
+	      return -EAI_SERVICE;
+	    }
 	}
     }
   while (r);
@@ -164,7 +169,7 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
   st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
 		  ? req->ai_protocol : tp->protocol);
   st->port = s->s_port;
-
+  scratch_buffer_free (&tmpbuf);
   return 0;
 }
 
@@ -178,25 +183,15 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
   no_data = 0;								      \
   while (1) {								      \
     rc = 0;								      \
-    status = DL_CALL_FCT (fct, (name, _family, &th, tmpbuf, tmpbuflen,	      \
+    status = DL_CALL_FCT (fct, (name, _family, &th,			      \
+				tmpbuf.data, tmpbuf.length,		      \
 				&rc, &herrno, NULL, &localcanon));	      \
     if (rc != ERANGE || herrno != NETDB_INTERNAL)			      \
       break;								      \
-    if (!malloc_tmpbuf && __libc_use_alloca (alloca_used + 2 * tmpbuflen))    \
-      tmpbuf = extend_alloca_account (tmpbuf, tmpbuflen, 2 * tmpbuflen,	      \
-				      alloca_used);			      \
-    else								      \
+    if (!scratch_buffer_grow (&tmpbuf))					      \
       {									      \
-	char *newp = realloc (malloc_tmpbuf ? tmpbuf : NULL,		      \
-			      2 * tmpbuflen);				      \
-	if (newp == NULL)						      \
-	  {								      \
-	    result = -EAI_MEMORY;					      \
-	    goto free_and_return;					      \
-	  }								      \
-	tmpbuf = newp;							      \
-	malloc_tmpbuf = true;						      \
-	tmpbuflen = 2 * tmpbuflen;					      \
+	result = -EAI_MEMORY;						      \
+	goto free_and_return;						      \
       }									      \
   }									      \
   if (status == NSS_STATUS_SUCCESS && rc == 0)				      \
@@ -280,7 +275,10 @@ gaih_inet (const char *name, const struct gaih_service *service,
   bool got_ipv6 = false;
   const char *canon = NULL;
   const char *orig_name = name;
-  size_t alloca_used = 0;
+
+  /* Reserve stack memory for this function's buffer and the one in
+     gaih_inet_serv.  */
+  size_t alloca_used = 2 * sizeof (struct scratch_buffer);
 
   if (req->ai_protocol || req->ai_socktype)
     {
@@ -401,9 +399,10 @@ gaih_inet (const char *name, const struct gaih_service *service,
   struct gaih_addrtuple *addrmem = NULL;
   bool malloc_canonbuf = false;
   char *canonbuf = NULL;
-  bool malloc_tmpbuf = false;
-  char *tmpbuf = NULL;
   int result = 0;
+  struct scratch_buffer tmpbuf;
+  scratch_buffer_init (&tmpbuf);
+
   if (name != NULL)
     {
       at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used);
@@ -571,11 +570,8 @@ gaih_inet (const char *name, const struct gaih_service *service,
 	  if (req->ai_family == AF_INET
 	      && (req->ai_flags & AI_CANONNAME) == 0)
 	    {
-	      /* Allocate additional room for struct host_data.  */
-	      size_t tmpbuflen = (512 + MAX_NR_ALIASES * sizeof(char*)
-				  + 16 * sizeof(char));
-	      assert (tmpbuf == NULL);
-	      tmpbuf = alloca_account (tmpbuflen, alloca_used);
+	      /* tmpbuf must not have been used so far.  */
+	      assert (tmpbuf.data == tmpbuf.__space);
 	      int rc;
 	      struct hostent th;
 	      struct hostent *h;
@@ -583,28 +579,15 @@ gaih_inet (const char *name, const struct gaih_service *service,
 
 	      while (1)
 		{
-		  rc = __gethostbyname2_r (name, AF_INET, &th, tmpbuf,
-					   tmpbuflen, &h, &herrno);
+		  rc = __gethostbyname2_r (name, AF_INET, &th,
+					   tmpbuf.data, tmpbuf.length,
+					   &h, &herrno);
 		  if (rc != ERANGE || herrno != NETDB_INTERNAL)
 		    break;
-
-		  if (!malloc_tmpbuf
-		      && __libc_use_alloca (alloca_used + 2 * tmpbuflen))
-		    tmpbuf = extend_alloca_account (tmpbuf, tmpbuflen,
-						    2 * tmpbuflen,
-						    alloca_used);
-		  else
+		  if (!scratch_buffer_grow (&tmpbuf))
 		    {
-		      char *newp = realloc (malloc_tmpbuf ? tmpbuf : NULL,
-					    2 * tmpbuflen);
-		      if (newp == NULL)
-			{
-			  result = -EAI_MEMORY;
-			  goto free_and_return;
-			}
-		      tmpbuf = newp;
-		      malloc_tmpbuf = true;
-		      tmpbuflen = 2 * tmpbuflen;
+		      result = -EAI_MEMORY;
+		      goto free_and_return;
 		    }
 		}
 
@@ -826,21 +809,8 @@ gaih_inet (const char *name, const struct gaih_service *service,
 	  old_res_options = _res.options;
 	  _res.options &= ~RES_USE_INET6;
 
-	  size_t tmpbuflen = 1024 + sizeof(struct gaih_addrtuple);
-	  malloc_tmpbuf = !__libc_use_alloca (alloca_used + tmpbuflen);
-	  assert (tmpbuf == NULL);
-	  if (!malloc_tmpbuf)
-	    tmpbuf = alloca_account (tmpbuflen, alloca_used);
-	  else
-	    {
-	      tmpbuf = malloc (tmpbuflen);
-	      if (tmpbuf == NULL)
-		{
-		  _res.options |= old_res_options & RES_USE_INET6;
-		  result = -EAI_MEMORY;
-		  goto free_and_return;
-		}
-	    }
+	  /* tmpbuf has not been used yet.  */
+	  assert (tmpbuf.data == tmpbuf.__space);
 
 	  while (!no_more)
 	    {
@@ -859,8 +829,9 @@ gaih_inet (const char *name, const struct gaih_service *service,
 		  while (1)
 		    {
 		      rc = 0;
-		      status = DL_CALL_FCT (fct4, (name, pat, tmpbuf,
-						   tmpbuflen, &rc, &herrno,
+		      status = DL_CALL_FCT (fct4, (name, pat,
+						   tmpbuf.data, tmpbuf.length,
+						   &rc, &herrno,
 						   NULL));
 		      if (status == NSS_STATUS_SUCCESS)
 			break;
@@ -874,24 +845,11 @@ gaih_inet (const char *name, const struct gaih_service *service,
 			  break;
 			}
 
-		      if (!malloc_tmpbuf
-			  && __libc_use_alloca (alloca_used + 2 * tmpbuflen))
-			tmpbuf = extend_alloca_account (tmpbuf, tmpbuflen,
-							2 * tmpbuflen,
-							alloca_used);
-		      else
+		      if (!scratch_buffer_grow (&tmpbuf))
 			{
-			  char *newp = realloc (malloc_tmpbuf ? tmpbuf : NULL,
-						2 * tmpbuflen);
-			  if (newp == NULL)
-			    {
-			      _res.options |= old_res_options & RES_USE_INET6;
-			      result = -EAI_MEMORY;
-			      goto free_and_return;
-			    }
-			  tmpbuf = newp;
-			  malloc_tmpbuf = true;
-			  tmpbuflen = 2 * tmpbuflen;
+			  _res.options |= old_res_options & RES_USE_INET6;
+			  result = -EAI_MEMORY;
+			  goto free_and_return;
 			}
 		    }
 
@@ -1278,8 +1236,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
     free (addrmem);
   if (malloc_canonbuf)
     free (canonbuf);
-  if (malloc_tmpbuf)
-    free (tmpbuf);
+  scratch_buffer_free (&tmpbuf);
 
   return result;
 }

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=d0d4ef12041b0d2feabd1d2d0376eecd0e1d7269

commit d0d4ef12041b0d2feabd1d2d0376eecd0e1d7269
Author: Florian Weimer <fweimer@redhat.com>
Date:   Sun Mar 1 19:14:29 2015 +0100

    getlogin_r (Linux variant): Switch to struct scratch_buffer
    
    This corrects the alloca accounting as a side effect.  It was not off
    if extend_alloca failed to merge allocations.
    
    	[BZ #18023]
    	* sysdeps/unix/sysv/linux/getlogin_r.c (__getlogin_r_loginuid):
    	Use struct scratch_buffer instead of extend_alloca.

diff --git a/sysdeps/unix/sysv/linux/getlogin_r.c b/sysdeps/unix/sysv/linux/getlogin_r.c
index 408907f..6e4c499 100644
--- a/sysdeps/unix/sysv/linux/getlogin_r.c
+++ b/sysdeps/unix/sysv/linux/getlogin_r.c
@@ -18,6 +18,7 @@
 #include <pwd.h>
 #include <unistd.h>
 #include <not-cancel.h>
+#include <scratch_buffer.h>
 
 #define STATIC static
 static int getlogin_r_fd0 (char *name, size_t namesize);
@@ -54,28 +55,19 @@ __getlogin_r_loginuid (char *name, size_t namesize)
 	  endp == uidbuf || *endp != '\0'))
     return -1;
 
-  size_t buflen = 1024;
-  char *buf = alloca (buflen);
-  bool use_malloc = false;
   struct passwd pwd;
   struct passwd *tpwd;
   int result = 0;
   int res;
+  struct scratch_buffer tmpbuf;
+  scratch_buffer_init (&tmpbuf);
 
-  while ((res = __getpwuid_r (uid, &pwd, buf, buflen, &tpwd)) == ERANGE)
-    if (__libc_use_alloca (2 * buflen))
-      buf = extend_alloca (buf, buflen, 2 * buflen);
-    else
+  while ((res = __getpwuid_r (uid, &pwd,
+			      tmpbuf.data, tmpbuf.length, &tpwd)) == ERANGE)
+    if (!scratch_buffer_grow (&tmpbuf))
       {
-	buflen *= 2;
-	char *newp = realloc (use_malloc ? buf : NULL, buflen);
-	if (newp == NULL)
-	  {
-	    result = ENOMEM;
-	    goto out;
-	  }
-	buf = newp;
-	use_malloc = true;
+	result = ENOMEM;
+	goto out;
       }
 
   if (res != 0 || tpwd == NULL)
@@ -95,9 +87,7 @@ __getlogin_r_loginuid (char *name, size_t namesize)
   memcpy (name, pwd.pw_name, needed);
 
  out:
-  if (use_malloc)
-    free (buf);
-
+  scratch_buffer_free (&tmpbuf);
   return result;
 }
 

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=e0f6d7eda4a9e33eacc1a3a68df2c9b747f3fdd9

commit e0f6d7eda4a9e33eacc1a3a68df2c9b747f3fdd9
Author: Florian Weimer <fweimer@redhat.com>
Date:   Sun Mar 1 19:11:55 2015 +0100

    gethostid (Linux variant): Switch to struct scratch_buffer
    
    Previously, extend_alloca was used without alloca accounting,
    which could have been problematic with large NSS results.
    
    	[BZ #18023]
    	* sysdeps/unix/sysv/linux/gethostid.c (gethostid): Use struct
    	scratch_buffer instead of extend_alloca.

diff --git a/sysdeps/unix/sysv/linux/gethostid.c b/sysdeps/unix/sysv/linux/gethostid.c
index 73e5c76..41c9b46 100644
--- a/sysdeps/unix/sysv/linux/gethostid.c
+++ b/sysdeps/unix/sysv/linux/gethostid.c
@@ -63,13 +63,12 @@ sethostid (long int id)
 # include <sys/param.h>
 # include <resolv/netdb.h>
 # include <netinet/in.h>
+# include <scratch_buffer.h>
 
 long int
 gethostid (void)
 {
   char hostname[MAXHOSTNAMELEN + 1];
-  size_t buflen;
-  char *buffer;
   struct hostent hostbuf, *hp;
   int32_t id;
   struct in_addr in;
@@ -94,23 +93,26 @@ gethostid (void)
     /* This also fails.  Return and arbitrary value.  */
     return 0;
 
-  buflen = 1024;
-  buffer = __alloca (buflen);
+  struct scratch_buffer tmpbuf;
+  scratch_buffer_init (&tmpbuf);
 
   /* To get the IP address we need to know the host name.  */
-  while (__gethostbyname_r (hostname, &hostbuf, buffer, buflen, &hp, &herr)
-	 != 0
+  while (__gethostbyname_r (hostname, &hostbuf,
+			    tmpbuf.data, tmpbuf.length, &hp, &herr) != 0
 	 || hp == NULL)
     if (herr != NETDB_INTERNAL || errno != ERANGE)
-      return 0;
+      {
+	scratch_buffer_free (&tmpbuf);
+	return 0;
+      }
     else
-      /* Enlarge buffer.  */
-      buffer = extend_alloca (buffer, buflen, 2 * buflen);
+      if (!scratch_buffer_grow (&tmpbuf))
+	return 0;
 
   in.s_addr = 0;
   memcpy (&in, hp->h_addr,
 	  (int) sizeof (in) < hp->h_length ? (int) sizeof (in) : hp->h_length);
-
+  scratch_buffer_free (&tmpbuf);
   /* For the return value to be not exactly the IP address we do some
      bit fiddling.  */
   return (int32_t) (in.s_addr << 16 | in.s_addr >> 16);

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=e970ea40df40ab5da24c984a0612f98a798221d8

commit e970ea40df40ab5da24c984a0612f98a798221d8
Author: Florian Weimer <fweimer@redhat.com>
Date:   Sun Mar 1 19:09:00 2015 +0100

    nss_files: Use struct scratch_buffer instead of extend_alloca
    
    In both _nss_files_gethostbyname3_r and _nss_files_initgroups_dyn,
    __libc_use_alloca was misused because it was not taken into account
    that extend_alloca can fail to merge allocations.
    
    	[BZ #18023]
    	* nss/nss_files/files-hosts.c (_nss_files_gethostbyname3_r):
    	Use struct scratch_buffer instead of extend_alloca.
    	* nss/nss_files/files-initgroups.c (_nss_files_initgroups_dyn):
    	Likewise.

diff --git a/nss/nss_files/files-hosts.c b/nss/nss_files/files-hosts.c
index 2a4a665..8eda308 100644
--- a/nss/nss_files/files-hosts.c
+++ b/nss/nss_files/files-hosts.c
@@ -22,7 +22,7 @@
 #include <arpa/nameser.h>
 #include <netdb.h>
 #include <resolv.h>
-
+#include <scratch_buffer.h>
 
 /* Get implementation for some internal functions.  */
 #include "../resolv/mapv4v6addr.h"
@@ -145,15 +145,12 @@ _nss_files_gethostbyname3_r (const char *name, int af, struct hostent *result,
 	  && _res_hconf.flags & HCONF_FLAG_MULTI)
 	{
 	  /* We have to get all host entries from the file.  */
-	  size_t tmp_buflen = MIN (buflen, 4096);
-	  char tmp_buffer_stack[tmp_buflen]
-	    __attribute__ ((__aligned__ (__alignof__ (struct hostent_data))));
-	  char *tmp_buffer = tmp_buffer_stack;
 	  struct hostent tmp_result_buf;
 	  int naddrs = 1;
 	  int naliases = 0;
 	  char *bufferend;
-	  bool tmp_buffer_malloced = false;
+	  struct scratch_buffer tmpbuf;
+	  scratch_buffer_init (&tmpbuf);
 
 	  while (result->h_aliases[naliases] != NULL)
 	    ++naliases;
@@ -161,9 +158,9 @@ _nss_files_gethostbyname3_r (const char *name, int af, struct hostent *result,
 	  bufferend = (char *) &result->h_aliases[naliases + 1];
 
 	again:
-	  while ((status = internal_getent (stream, &tmp_result_buf, tmp_buffer,
-					    tmp_buflen, errnop, herrnop, af,
-					    flags))
+	  while ((status = internal_getent (stream, &tmp_result_buf,
+					    tmpbuf.data, tmpbuf.length,
+					    errnop, herrnop, af, flags))
 		 == NSS_STATUS_SUCCESS)
 	    {
 	      int matches = 1;
@@ -287,54 +284,13 @@ _nss_files_gethostbyname3_r (const char *name, int af, struct hostent *result,
 		}
 	    }
 
-	  if (status == NSS_STATUS_TRYAGAIN)
-	    {
-	      size_t newsize = 2 * tmp_buflen;
-	      if (tmp_buffer_malloced)
-		{
-		  char *newp = realloc (tmp_buffer, newsize);
-		  if (newp != NULL)
-		    {
-		      assert ((((uintptr_t) newp)
-			       & (__alignof__ (struct hostent_data) - 1))
-			      == 0);
-		      tmp_buffer = newp;
-		      tmp_buflen = newsize;
-		      goto again;
-		    }
-		}
-	      else if (!__libc_use_alloca (buflen + newsize))
-		{
-		  tmp_buffer = malloc (newsize);
-		  if (tmp_buffer != NULL)
-		    {
-		      assert ((((uintptr_t) tmp_buffer)
-			       & (__alignof__ (struct hostent_data) - 1))
-			      == 0);
-		      tmp_buffer_malloced = true;
-		      tmp_buflen = newsize;
-		      goto again;
-		    }
-		}
-	      else
-		{
-		  tmp_buffer
-		    = extend_alloca (tmp_buffer, tmp_buflen,
-				     newsize
-				     + __alignof__ (struct hostent_data));
-		  tmp_buffer = (char *) (((uintptr_t) tmp_buffer
-					  + __alignof__ (struct hostent_data)
-					  - 1)
-					 & ~(__alignof__ (struct hostent_data)
-					     - 1));
-		  goto again;
-		}
-	    }
+	  if (status == NSS_STATUS_TRYAGAIN
+	      && scratch_buffer_grow (&tmpbuf))
+	    goto again;
 	  else
 	    status = NSS_STATUS_SUCCESS;
 	out:
-	  if (tmp_buffer_malloced)
-	    free (tmp_buffer);
+	  scratch_buffer_free (&tmpbuf);
 	}
 
       internal_endent (&stream);
diff --git a/nss/nss_files/files-initgroups.c b/nss/nss_files/files-initgroups.c
index 6e0d825..13d45cc 100644
--- a/nss/nss_files/files-initgroups.c
+++ b/nss/nss_files/files-initgroups.c
@@ -16,7 +16,6 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <alloca.h>
 #include <errno.h>
 #include <grp.h>
 #include <nss.h>
@@ -25,6 +24,7 @@
 #include <sys/param.h>
 #include <stdbool.h>
 #include <stdlib.h>
+#include <scratch_buffer.h>
 
 enum nss_status
 _nss_files_initgroups_dyn (const char *user, gid_t group, long int *start,
@@ -46,9 +46,8 @@ _nss_files_initgroups_dyn (const char *user, gid_t group, long int *start,
   enum nss_status status = NSS_STATUS_SUCCESS;
   bool any = false;
 
-  size_t buflen = 1024;
-  void *buffer = alloca (buflen);
-  bool buffer_use_malloc = false;
+  struct scratch_buffer tmpbuf;
+  scratch_buffer_init (&tmpbuf);
 
   gid_t *groups = *groupsp;
 
@@ -67,26 +66,16 @@ _nss_files_initgroups_dyn (const char *user, gid_t group, long int *start,
 	}
 
       struct group grp;
-      int res = _nss_files_parse_grent (line, &grp, buffer, buflen, errnop);
+      int res = _nss_files_parse_grent (line, &grp,
+					tmpbuf.data, tmpbuf.length, errnop);
       if (res == -1)
 	{
-	  size_t newbuflen = 2 * buflen;
-	  if (buffer_use_malloc || ! __libc_use_alloca (buflen + newbuflen))
+	  if (!scratch_buffer_grow (&tmpbuf))
 	    {
-	      void *newbuf = realloc (buffer_use_malloc ? buffer : NULL,
-				      newbuflen);
-	      if (newbuf == NULL)
-		{
-		  *errnop = ENOMEM;
-		  status = NSS_STATUS_TRYAGAIN;
-		  goto out;
-		}
-	      buffer = newbuf;
-	      buflen = newbuflen;
-	      buffer_use_malloc = true;
+	      *errnop = ENOMEM;
+	      status = NSS_STATUS_TRYAGAIN;
+	      goto out;
 	    }
-	  else
-	    buffer = extend_alloca (buffer, buflen, newbuflen);
 	  /* Reread current line, the parser has clobbered it.  */
 	  fsetpos (stream, &pos);
 	  continue;
@@ -132,8 +121,7 @@ _nss_files_initgroups_dyn (const char *user, gid_t group, long int *start,
 
  out:
   /* Free memory.  */
-  if (buffer_use_malloc)
-    free (buffer);
+  scratch_buffer_free (&tmpbuf);
   free (line);
 
   fclose (stream);

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=34ddffb50c2d2159c152cc34516f4c4088b3cc36

commit 34ddffb50c2d2159c152cc34516f4c4088b3cc36
Author: Florian Weimer <fweimer@redhat.com>
Date:   Sun Mar 1 19:03:01 2015 +0100

    getent: Switch to struct scratch_buffer in initgroups_keys
    
    The retry loop is slightly different here because getgrouplist
    provides size information, so scratch_buffer_set_array_size can be
    used to grow the buffer in a more precise fashion.
    
    	[BZ #18023]
    	* nss/getent.c (initgroups_keys): Use struct scratch_buffer
    	instead of extend_alloca.

diff --git a/nss/getent.c b/nss/getent.c
index de7b83f..e85d761 100644
--- a/nss/getent.c
+++ b/nss/getent.c
@@ -39,6 +39,7 @@
 #include <netinet/ether.h>
 #include <netinet/in.h>
 #include <sys/socket.h>
+#include <scratch_buffer.h>
 
 /* Get libc version number.  */
 #include <version.h>
@@ -477,30 +478,34 @@ netgroup_keys (int number, char *key[])
 static int
 initgroups_keys (int number, char *key[])
 {
-  int ngrps = 100;
-  size_t grpslen = ngrps * sizeof (gid_t);
-  gid_t *grps = alloca (grpslen);
-
   if (number == 0)
     {
       fprintf (stderr, _("Enumeration not supported on %s\n"), "initgroups");
       return 3;
     }
 
+  struct scratch_buffer tmpbuf;
+  scratch_buffer_init (&tmpbuf);
+
   for (int i = 0; i < number; ++i)
     {
+      ssize_t ngrps = tmpbuf.length / sizeof (gid_t);
       int no = ngrps;
       int n;
-      while ((n = getgrouplist (key[i], -1, grps, &no)) == -1
+      while ((n = getgrouplist (key[i], -1, tmpbuf.data, &no)) == -1
 	     && no > ngrps)
 	{
-	  grps = extend_alloca (grps, grpslen, no * sizeof (gid_t));
-	  ngrps = no;
+	  if (!scratch_buffer_set_array_size (&tmpbuf, no, sizeof (gid_t)))
+	    {
+	      fprintf (stderr, _("Could not allocate group list: %m\n"));
+	      return 3;
+	    }
 	}
 
       if (n == -1)
 	return 1;
 
+      const gid_t *grps = tmpbuf.data;
       printf ("%-21s", key[i]);
       for (int j = 0; j < n; ++j)
 	if (grps[j] != -1)
@@ -508,6 +513,8 @@ initgroups_keys (int number, char *key[])
       putchar_unlocked ('\n');
     }
 
+  scratch_buffer_free (&tmpbuf);
+
   return 0;
 }
 

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=4e10cf98c38e471f1c0637150c51fa2935b271fa

commit 4e10cf98c38e471f1c0637150c51fa2935b271fa
Author: Florian Weimer <fweimer@redhat.com>
Date:   Sun Mar 1 18:59:48 2015 +0100

    nscd: Switch to struct scratch_buffer in adhstaiX
    
    The pre-allocation of the three scratch buffers increased the initial
    stack size somewhat, but if retries are needed, the previous version
    used more stack space if extend_alloca could not merge allocations.
    Lack of alloca accounting also means could be problematic with
    extremely large NSS responses, too.
    
    	[BZ #18023]
    	* nscd/aicache.c (addhstaiX): Use struct scratch_buffer instead
    	of extend_alloca.

diff --git a/nscd/aicache.c b/nscd/aicache.c
index a2e6cf8..e181fdc 100644
--- a/nscd/aicache.c
+++ b/nscd/aicache.c
@@ -26,6 +26,7 @@
 #include <unistd.h>
 #include <sys/mman.h>
 #include <resolv/res_hconf.h>
+#include <scratch_buffer.h>
 
 #include "dbg_log.h"
 #include "nscd.h"
@@ -113,10 +114,13 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
   int old_res_options = _res.options;
   _res.options &= ~RES_USE_INET6;
 
-  size_t tmpbuf6len = 1024;
-  char *tmpbuf6 = alloca (tmpbuf6len);
-  size_t tmpbuf4len = 0;
-  char *tmpbuf4 = NULL;
+  struct scratch_buffer tmpbuf6;
+  scratch_buffer_init (&tmpbuf6);
+  struct scratch_buffer tmpbuf4;
+  scratch_buffer_init (&tmpbuf4);
+  struct scratch_buffer canonbuf;
+  scratch_buffer_init (&canonbuf);
+
   int32_t ttl = INT32_MAX;
   ssize_t total = 0;
   char *key_copy = NULL;
@@ -129,6 +133,7 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
       int status[2] = { NSS_STATUS_UNAVAIL, NSS_STATUS_UNAVAIL };
       int naddrs = 0;
       size_t addrslen = 0;
+
       char *canon = NULL;
       size_t canonlen;
 
@@ -143,12 +148,17 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
 	      at = &atmem;
 	      rc6 = 0;
 	      herrno = 0;
-	      status[1] = DL_CALL_FCT (fct4, (key, &at, tmpbuf6, tmpbuf6len,
+	      status[1] = DL_CALL_FCT (fct4, (key, &at,
+					      tmpbuf6.data, tmpbuf6.length,
 					      &rc6, &herrno, &ttl));
 	      if (rc6 != ERANGE || (herrno != NETDB_INTERNAL
 				    && herrno != TRY_AGAIN))
 		break;
-	      tmpbuf6 = extend_alloca (tmpbuf6, tmpbuf6len, 2 * tmpbuf6len);
+	      if (!scratch_buffer_grow (&tmpbuf6))
+		{
+		  rc6 = ENOMEM;
+		  break;
+		}
 	    }
 
 	  if (rc6 != 0 && herrno == NETDB_INTERNAL)
@@ -226,41 +236,38 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
 	  while (1)
 	    {
 	      rc6 = 0;
-	      status[0] = DL_CALL_FCT (fct, (key, AF_INET6, &th[0], tmpbuf6,
-					     tmpbuf6len, &rc6, &herrno, &ttl,
+	      status[0] = DL_CALL_FCT (fct, (key, AF_INET6, &th[0],
+					     tmpbuf6.data, tmpbuf6.length,
+					     &rc6, &herrno, &ttl,
 					     &canon));
 	      if (rc6 != ERANGE || herrno != NETDB_INTERNAL)
 		break;
-	      tmpbuf6 = extend_alloca (tmpbuf6, tmpbuf6len, 2 * tmpbuf6len);
+	      if (!scratch_buffer_grow (&tmpbuf6))
+		{
+		  rc6 = ENOMEM;
+		  break;
+		}
 	    }
 
 	  if (rc6 != 0 && herrno == NETDB_INTERNAL)
 	    goto out;
 
-	  /* If the IPv6 lookup has been successful do not use the
-	     buffer used in that lookup, use a new one.  */
-	  if (status[0] == NSS_STATUS_SUCCESS && rc6 == 0)
-	    {
-	      tmpbuf4len = 512;
-	      tmpbuf4 = alloca (tmpbuf4len);
-	    }
-	  else
-	    {
-	      tmpbuf4len = tmpbuf6len;
-	      tmpbuf4 = tmpbuf6;
-	    }
-
 	  /* Next collect IPv4 information.  */
 	  while (1)
 	    {
 	      rc4 = 0;
-	      status[1] = DL_CALL_FCT (fct, (key, AF_INET, &th[1], tmpbuf4,
-					     tmpbuf4len, &rc4, &herrno,
+	      status[1] = DL_CALL_FCT (fct, (key, AF_INET, &th[1],
+					     tmpbuf4.data, tmpbuf4.length,
+					     &rc4, &herrno,
 					     ttl == INT32_MAX ? &ttl : NULL,
 					     canon == NULL ? &canon : NULL));
 	      if (rc4 != ERANGE || herrno != NETDB_INTERNAL)
 		break;
-	      tmpbuf4 = extend_alloca (tmpbuf4, tmpbuf4len, 2 * tmpbuf4len);
+	      if (!scratch_buffer_grow (&tmpbuf4))
+		{
+		  rc4 = ENOMEM;
+		  break;
+		}
 	    }
 
 	  if (rc4 != 0 && herrno == NETDB_INTERNAL)
@@ -286,13 +293,11 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
 	      cfct = __nss_lookup_function (nip, "getcanonname_r");
 	      if (cfct != NULL)
 		{
-		  const size_t max_fqdn_len = 256;
-		  char *buf = alloca (max_fqdn_len);
 		  char *s;
 		  int rc;
 
-		  if (DL_CALL_FCT (cfct, (key, buf, max_fqdn_len, &s,
-					  &rc, &herrno))
+		  if (DL_CALL_FCT (cfct, (key, canonbuf.data, canonbuf.length,
+					  &s, &rc, &herrno))
 		      == NSS_STATUS_SUCCESS)
 		    canon = s;
 		  else
@@ -321,18 +326,20 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
 		      addrfamily = AF_INET6;
 		    }
 
-		  size_t tmpbuflen = 512;
-		  char *tmpbuf = alloca (tmpbuflen);
 		  int rc;
 		  while (1)
 		    {
 		      rc = __gethostbyaddr2_r (addr, addrlen, addrfamily,
-					       &hstent_mem, tmpbuf, tmpbuflen,
+					       &hstent_mem,
+					       canonbuf.data, canonbuf.length,
 					       &hstent, &herrno, NULL);
 		      if (rc != ERANGE || herrno != NETDB_INTERNAL)
 			break;
-		      tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
-					      tmpbuflen * 2);
+		      if (!scratch_buffer_grow (&canonbuf))
+			{
+			  rc = ENOMEM;
+			  break;
+			}
 		    }
 
 		  if (rc == 0)
@@ -560,6 +567,10 @@ next_nip:
 	dh->usable = false;
     }
 
+  scratch_buffer_free (&tmpbuf6);
+  scratch_buffer_free (&tmpbuf4);
+  scratch_buffer_free (&canonbuf);
+
   return timeout;
 }
 

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=4e0898ab1bd8502cf4acbbe82c1755127b561ae8

commit 4e0898ab1bd8502cf4acbbe82c1755127b561ae8
Author: Florian Weimer <fweimer@redhat.com>
Date:   Sun Mar 1 18:55:33 2015 +0100

    nscd: Use struct scratch_buffer instead of extend_alloca in most caches
    
    This replaces the ERANGE retry loops with loops which have heap
    fallback.  Heap allocation might actually be required for extremely
    large NSS results.
    
    	[BZ #18023]
    	* nscd/grpcache.c (addgrbyX): Use struct scratch_buffer instead
    	of extend_alloca.
    	* nscd/hstcache.c (addhstbyX): Likewise.
    	* nscd/pwdcache.c (addpwbyX): Likewise.
    	* nscd/servicescache.c (addservbyX): Likewise.

diff --git a/nscd/grpcache.c b/nscd/grpcache.c
index 3831170..53a912b 100644
--- a/nscd/grpcache.c
+++ b/nscd/grpcache.c
@@ -16,7 +16,6 @@
    You should have received a copy of the GNU General Public License
    along with this program; if not, see <http://www.gnu.org/licenses/>.  */
 
-#include <alloca.h>
 #include <assert.h>
 #include <errno.h>
 #include <error.h>
@@ -32,6 +31,7 @@
 #include <sys/mman.h>
 #include <sys/socket.h>
 #include <stackinfo.h>
+#include <scratch_buffer.h>
 
 #include "nscd.h"
 #include "dbg_log.h"
@@ -437,12 +437,12 @@ addgrbyX (struct database_dyn *db, int fd, request_header *req,
      look again in the table whether the dataset is now available.  We
      simply insert it.  It does not matter if it is in there twice.  The
      pruning function only will look at the timestamp.  */
-  size_t buflen = 1024;
-  char *buffer = (char *) alloca (buflen);
+
   struct group resultbuf;
   struct group *grp;
-  bool use_malloc = false;
   int errval = 0;
+  struct scratch_buffer tmpbuf;
+  scratch_buffer_init (&tmpbuf);
 
   if (__glibc_unlikely (debug_level > 0))
     {
@@ -452,43 +452,24 @@ addgrbyX (struct database_dyn *db, int fd, request_header *req,
 	dbg_log (_("Reloading \"%s\" in group cache!"), keystr);
     }
 
-  while (lookup (req->type, key, &resultbuf, buffer, buflen, &grp) != 0
+  while (lookup (req->type, key, &resultbuf,
+		 tmpbuf.data, tmpbuf.length, &grp) != 0
 	 && (errval = errno) == ERANGE)
-    {
-      errno = 0;
-
-      if (__glibc_unlikely (buflen > 32768))
-	{
-	  char *old_buffer = buffer;
-	  buflen *= 2;
-	  buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
-	  if (buffer == NULL)
-	    {
-	      /* We ran out of memory.  We cannot do anything but
-		 sending a negative response.  In reality this should
-		 never happen.  */
-	      grp = NULL;
-	      buffer = old_buffer;
-
-	      /* We set the error to indicate this is (possibly) a
-		 temporary error and that it does not mean the entry
-		 is not available at all.  */
-	      errval = EAGAIN;
-	      break;
-	    }
-	  use_malloc = true;
-	}
-      else
-	/* Allocate a new buffer on the stack.  If possible combine it
-	   with the previously allocated buffer.  */
-	buffer = (char *) extend_alloca (buffer, buflen, 2 * buflen);
-    }
+    if (!scratch_buffer_grow (&tmpbuf))
+      {
+	/* We ran out of memory.  We cannot do anything but sending a
+	   negative response.  In reality this should never
+	   happen.  */
+	grp = NULL;
+	/* We set the error to indicate this is (possibly) a temporary
+	   error and that it does not mean the entry is not available
+	   at all.  */
+	errval = EAGAIN;
+	break;
+      }
 
   time_t timeout = cache_addgr (db, fd, req, keystr, grp, uid, he, dh, errval);
-
-  if (use_malloc)
-    free (buffer);
-
+  scratch_buffer_free (&tmpbuf);
   return timeout;
 }
 
diff --git a/nscd/hstcache.c b/nscd/hstcache.c
index 04708ed..4ad4e87 100644
--- a/nscd/hstcache.c
+++ b/nscd/hstcache.c
@@ -34,6 +34,7 @@
 #include <arpa/nameser.h>
 #include <sys/mman.h>
 #include <stackinfo.h>
+#include <scratch_buffer.h>
 
 #include "nscd.h"
 #include "dbg_log.h"
@@ -463,11 +464,8 @@ addhstbyX (struct database_dyn *db, int fd, request_header *req,
      look again in the table whether the dataset is now available.  We
      simply insert it.  It does not matter if it is in there twice.  The
      pruning function only will look at the timestamp.  */
-  int buflen = 1024;
-  char *buffer = (char *) alloca (buflen);
   struct hostent resultbuf;
   struct hostent *hst;
-  bool use_malloc = false;
   int errval = 0;
   int32_t ttl = INT32_MAX;
 
@@ -487,46 +485,30 @@ addhstbyX (struct database_dyn *db, int fd, request_header *req,
 	dbg_log (_("Reloading \"%s\" in hosts cache!"), (char *) str);
     }
 
-  while (lookup (req->type, key, &resultbuf, buffer, buflen, &hst, &ttl) != 0
+  struct scratch_buffer tmpbuf;
+  scratch_buffer_init (&tmpbuf);
+
+  while (lookup (req->type, key, &resultbuf,
+		 tmpbuf.data, tmpbuf.length, &hst, &ttl) != 0
 	 && h_errno == NETDB_INTERNAL
 	 && (errval = errno) == ERANGE)
-    {
-      errno = 0;
-
-      if (__glibc_unlikely (buflen > 32768))
-	{
-	  char *old_buffer = buffer;
-	  buflen *= 2;
-	  buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
-	  if (buffer == NULL)
-	    {
-	      /* We ran out of memory.  We cannot do anything but
-		 sending a negative response.  In reality this should
-		 never happen.  */
-	      hst = NULL;
-	      buffer = old_buffer;
-
-	      /* We set the error to indicate this is (possibly) a
-		 temporary error and that it does not mean the entry
-		 is not available at all.  */
-	      h_errno = TRY_AGAIN;
-	      errval = EAGAIN;
-	      break;
-	    }
-	  use_malloc = true;
-	}
-      else
-	/* Allocate a new buffer on the stack.  If possible combine it
-	   with the previously allocated buffer.  */
-	buffer = (char *) extend_alloca (buffer, buflen, 2 * buflen);
-    }
+    if (!scratch_buffer_grow (&tmpbuf))
+      {
+	/* We ran out of memory.  We cannot do anything but sending a
+	   negative response.  In reality this should never
+	   happen.  */
+	hst = NULL;
+	/* We set the error to indicate this is (possibly) a temporary
+	   error and that it does not mean the entry is not
+	   available at all.  */
+	h_errno = TRY_AGAIN;
+	errval = EAGAIN;
+	break;
+      }
 
   time_t timeout = cache_addhst (db, fd, req, key, hst, uid, he, dh,
 				 h_errno == TRY_AGAIN ? errval : 0, ttl);
-
-  if (use_malloc)
-    free (buffer);
-
+  scratch_buffer_free (&tmpbuf);
   return timeout;
 }
 
diff --git a/nscd/pwdcache.c b/nscd/pwdcache.c
index 6dd6746..0b0f52e 100644
--- a/nscd/pwdcache.c
+++ b/nscd/pwdcache.c
@@ -16,7 +16,6 @@
    You should have received a copy of the GNU General Public License
    along with this program; if not, see <http://www.gnu.org/licenses/>.  */
 
-#include <alloca.h>
 #include <assert.h>
 #include <errno.h>
 #include <error.h>
@@ -32,6 +31,7 @@
 #include <sys/mman.h>
 #include <sys/socket.h>
 #include <stackinfo.h>
+#include <scratch_buffer.h>
 
 #include "nscd.h"
 #include "dbg_log.h"
@@ -415,12 +415,11 @@ addpwbyX (struct database_dyn *db, int fd, request_header *req,
      look again in the table whether the dataset is now available.  We
      simply insert it.  It does not matter if it is in there twice.  The
      pruning function only will look at the timestamp.  */
-  size_t buflen = 1024;
-  char *buffer = (char *) alloca (buflen);
   struct passwd resultbuf;
   struct passwd *pwd;
-  bool use_malloc = false;
   int errval = 0;
+  struct scratch_buffer tmpbuf;
+  scratch_buffer_init (&tmpbuf);
 
   if (__glibc_unlikely (debug_level > 0))
     {
@@ -430,45 +429,26 @@ addpwbyX (struct database_dyn *db, int fd, request_header *req,
 	dbg_log (_("Reloading \"%s\" in password cache!"), keystr);
     }
 
-  while (lookup (req->type, key, &resultbuf, buffer, buflen, &pwd) != 0
+  while (lookup (req->type, key, &resultbuf,
+		 tmpbuf.data, tmpbuf.length, &pwd) != 0
 	 && (errval = errno) == ERANGE)
-    {
-      errno = 0;
-
-      if (__glibc_unlikely (buflen > 32768))
-	{
-	  char *old_buffer = buffer;
-	  buflen *= 2;
-	  buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
-	  if (buffer == NULL)
-	    {
-	      /* We ran out of memory.  We cannot do anything but
-		 sending a negative response.  In reality this should
-		 never happen.  */
-	      pwd = NULL;
-	      buffer = old_buffer;
-
-	      /* We set the error to indicate this is (possibly) a
-		 temporary error and that it does not mean the entry
-		 is not available at all.  */
-	      errval = EAGAIN;
-	      break;
-	    }
-	  use_malloc = true;
-	}
-      else
-	/* Allocate a new buffer on the stack.  If possible combine it
-	   with the previously allocated buffer.  */
-	buffer = (char *) extend_alloca (buffer, buflen, 2 * buflen);
-    }
+    if (!scratch_buffer_grow (&tmpbuf))
+      {
+	/* We ran out of memory.  We cannot do anything but sending a
+	   negative response.  In reality this should never
+	   happen.  */
+	pwd = NULL;
+	/* We set the error to indicate this is (possibly) a temporary
+	   error and that it does not mean the entry is not available
+	   at all.  */
+	errval = EAGAIN;
+	break;
+      }
 
   /* Add the entry to the cache.  */
   time_t timeout = cache_addpw (db, fd, req, keystr, pwd, c_uid, he, dh,
 				errval);
-
-  if (use_malloc)
-    free (buffer);
-
+  scratch_buffer_free (&tmpbuf);
   return timeout;
 }
 
diff --git a/nscd/servicescache.c b/nscd/servicescache.c
index 00a2353..f90312d 100644
--- a/nscd/servicescache.c
+++ b/nscd/servicescache.c
@@ -16,7 +16,6 @@
    You should have received a copy of the GNU General Public License
    along with this program; if not, see <http://www.gnu.org/licenses/>.  */
 
-#include <alloca.h>
 #include <assert.h>
 #include <errno.h>
 #include <libintl.h>
@@ -25,6 +24,7 @@
 #include <stdint.h>
 #include <sys/mman.h>
 #include <kernel-features.h>
+#include <scratch_buffer.h>
 
 #include "nscd.h"
 #include "dbg_log.h"
@@ -374,12 +374,11 @@ addservbyX (struct database_dyn *db, int fd, request_header *req,
      look again in the table whether the dataset is now available.  We
      simply insert it.  It does not matter if it is in there twice.  The
      pruning function only will look at the timestamp.  */
-  size_t buflen = 1024;
-  char *buffer = (char *) alloca (buflen);
   struct servent resultbuf;
   struct servent *serv;
-  bool use_malloc = false;
   int errval = 0;
+  struct scratch_buffer tmpbuf;
+  scratch_buffer_init (&tmpbuf);
 
   if (__glibc_unlikely (debug_level > 0))
     {
@@ -389,43 +388,24 @@ addservbyX (struct database_dyn *db, int fd, request_header *req,
 	dbg_log (_("Reloading \"%s\" in services cache!"), key);
     }
 
-  while (lookup (req->type, key, &resultbuf, buffer, buflen, &serv) != 0
+  while (lookup (req->type, key, &resultbuf,
+		 tmpbuf.data, tmpbuf.length, &serv) != 0
 	 && (errval = errno) == ERANGE)
-    {
-      errno = 0;
-
-      if (__glibc_unlikely (buflen > 32768))
-	{
-	  char *old_buffer = buffer;
-	  buflen *= 2;
-	  buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
-	  if (buffer == NULL)
-	    {
-	      /* We ran out of memory.  We cannot do anything but
-		 sending a negative response.  In reality this should
-		 never happen.  */
-	      serv = NULL;
-	      buffer = old_buffer;
-
-	      /* We set the error to indicate this is (possibly) a
-		 temporary error and that it does not mean the entry
-		 is not available at all.  */
-	      errval = EAGAIN;
-	      break;
-	    }
-	  use_malloc = true;
-	}
-      else
-	/* Allocate a new buffer on the stack.  If possible combine it
-	   with the previously allocated buffer.  */
-	buffer = (char *) extend_alloca (buffer, buflen, 2 * buflen);
-    }
+    if (!scratch_buffer_grow (&tmpbuf))
+      {
+	/* We ran out of memory.  We cannot do anything but sending a
+	   negative response.  In reality this should never
+	   happen.  */
+	serv = NULL;
+	/* We set the error to indicate this is (possibly) a temporary
+	   error and that it does not mean the entry is not available
+	   at all.  */
+	errval = EAGAIN;
+	break;
+      }
 
   time_t timeout = cache_addserv (db, fd, req, key, serv, uid, he, dh, errval);
-
-  if (use_malloc)
-    free (buffer);
-
+  scratch_buffer_free (&tmpbuf);
   return timeout;
 }
 

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=05c4a3d37270334b1bacb4b9b97943167c062ace

commit 05c4a3d37270334b1bacb4b9b97943167c062ace
Author: Florian Weimer <fweimer@redhat.com>
Date:   Sun Mar 1 16:18:21 2015 +0100

    _nss_nis_initgroups_dyn: Use struct scratch_buffer instead of extend_alloca
    
    Also adjusts the internal function get_uid.
    
    	[BZ #18023]
            * nis/nss_nis/nis-initgroups.c (get_uid, _nss_nis_initgroups_dyn):
    	Use struct scratch_buffer instead of extend_alloca.

diff --git a/nis/nss_nis/nis-initgroups.c b/nis/nss_nis/nis-initgroups.c
index dec385c..9a3ac36 100644
--- a/nis/nss_nis/nis-initgroups.c
+++ b/nis/nss_nis/nis-initgroups.c
@@ -16,7 +16,6 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <alloca.h>
 #include <ctype.h>
 #include <errno.h>
 #include <grp.h>
@@ -27,6 +26,7 @@
 #include <rpcsvc/yp.h>
 #include <rpcsvc/ypclnt.h>
 #include <sys/param.h>
+#include <scratch_buffer.h>
 
 #include "nss-nis.h"
 #include <libnsl.h>
@@ -120,27 +120,30 @@ internal_getgrent_r (struct group *grp, char *buffer, size_t buflen,
 static int
 get_uid (const char *user, uid_t *uidp)
 {
-  size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX);
-  char *buf = (char *) alloca (buflen);
+  struct scratch_buffer tmpbuf;
+  scratch_buffer_init (&tmpbuf);
 
   while (1)
     {
       struct passwd result;
       struct passwd *resp;
 
-      int r = getpwnam_r (user, &result, buf, buflen, &resp);
+      int r = getpwnam_r (user, &result, tmpbuf.data, tmpbuf.length, &resp);
       if (r == 0 && resp != NULL)
 	{
 	  *uidp = resp->pw_uid;
+	  scratch_buffer_free (&tmpbuf);
 	  return 0;
 	}
 
       if (r != ERANGE)
 	break;
 
-      buf = extend_alloca (buf, buflen, 2 * buflen);
+      if (!scratch_buffer_grow (&tmpbuf))
+	return 1;
     }
 
+  scratch_buffer_free (&tmpbuf);
   return 1;
 }
 
@@ -254,8 +257,6 @@ _nss_nis_initgroups_dyn (const char *user, gid_t group, long int *start,
     }
 
   struct group grpbuf, *g;
-  size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX);
-  char *tmpbuf;
   enum nss_status status;
   intern_t intern = { NULL, NULL, 0 };
   gid_t *groups = *groupsp;
@@ -264,15 +265,20 @@ _nss_nis_initgroups_dyn (const char *user, gid_t group, long int *start,
   if (status != NSS_STATUS_SUCCESS)
     return status;
 
-  tmpbuf = __alloca (buflen);
+  struct scratch_buffer tmpbuf;
+  scratch_buffer_init (&tmpbuf);
 
   do
     {
       while ((status =
-	      internal_getgrent_r (&grpbuf, tmpbuf, buflen, errnop,
+	      internal_getgrent_r (&grpbuf, tmpbuf.data, tmpbuf.length, errnop,
 				   &intern)) == NSS_STATUS_TRYAGAIN
              && *errnop == ERANGE)
-	tmpbuf = extend_alloca (tmpbuf, buflen, 2 * buflen);
+	if (!scratch_buffer_grow (&tmpbuf))
+	  {
+	    status = NSS_STATUS_TRYAGAIN;
+	    goto done;
+	  }
 
       if (status != NSS_STATUS_SUCCESS)
 	goto done;
@@ -325,6 +331,7 @@ done:
       intern.start = intern.start->next;
       free (intern.next);
     }
+  scratch_buffer_free (&tmpbuf);
 
   return status;
 }

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=36ce46f76904ba86adb37836d0abe6e88faa4f74

commit 36ce46f76904ba86adb37836d0abe6e88faa4f74
Author: Florian Weimer <fweimer@redhat.com>
Date:   Sun Mar 1 16:03:01 2015 +0100

    _dl_map_object_deps: Use struct scratch_buffer instead of extend_alloca
    
    The function comment suggests that _dl_map_object_deps cannot use
    malloc, but it already allocates the l_initfini array on the heap, so
    the additional allocation should be acceptable.
    
    	[BZ #18023]
    	* elf/dl-deps.c (_dl_map_object_deps): Use struct
    	scratch_buffer instead of extend_alloca.

diff --git a/elf/dl-deps.c b/elf/dl-deps.c
index 6a82987..1458545 100644
--- a/elf/dl-deps.c
+++ b/elf/dl-deps.c
@@ -27,6 +27,7 @@
 #include <unistd.h>
 #include <sys/param.h>
 #include <ldsodefs.h>
+#include <scratch_buffer.h>
 
 #include <dl-dst.h>
 
@@ -184,9 +185,8 @@ _dl_map_object_deps (struct link_map *map,
   /* Pointer to last unique object.  */
   tail = &known[nlist - 1];
 
-  /* No alloca'd space yet.  */
-  struct link_map **needed_space = NULL;
-  size_t needed_space_bytes = 0;
+  struct scratch_buffer needed_space;
+  scratch_buffer_init (&needed_space);
 
   /* Process each element of the search list, loading each of its
      auxiliary objects and immediate dependencies.  Auxiliary objects
@@ -217,13 +217,12 @@ _dl_map_object_deps (struct link_map *map,
       if (l->l_searchlist.r_list == NULL && l->l_initfini == NULL
 	  && l != map && l->l_ldnum > 0)
 	{
-	  size_t new_size = l->l_ldnum * sizeof (struct link_map *);
-
-	  if (new_size > needed_space_bytes)
-	    needed_space
-	      = extend_alloca (needed_space, needed_space_bytes, new_size);
-
-	  needed = needed_space;
+	  /* l->l_ldnum includes space for the terminating NULL.  */
+	  if (!scratch_buffer_set_array_size
+	      (&needed_space, l->l_ldnum, sizeof (struct link_map *)))
+	    _dl_signal_error (ENOMEM, map->l_name, NULL,
+			      N_("cannot allocate dependency buffer"));
+	  needed = needed_space.data;
 	}
 
       if (l->l_info[DT_NEEDED] || l->l_info[AUXTAG] || l->l_info[FILTERTAG])
@@ -463,8 +462,11 @@ _dl_map_object_deps (struct link_map *map,
 	  struct link_map **l_initfini = (struct link_map **)
 	    malloc ((2 * nneeded + 1) * sizeof needed[0]);
 	  if (l_initfini == NULL)
-	    _dl_signal_error (ENOMEM, map->l_name, NULL,
-			      N_("cannot allocate dependency list"));
+	    {
+	      scratch_buffer_free (&needed_space);
+	      _dl_signal_error (ENOMEM, map->l_name, NULL,
+				N_("cannot allocate dependency list"));
+	    }
 	  l_initfini[0] = l;
 	  memcpy (&l_initfini[1], needed, nneeded * sizeof needed[0]);
 	  memcpy (&l_initfini[nneeded + 1], l_initfini,
@@ -482,6 +484,8 @@ _dl_map_object_deps (struct link_map *map,
     }
 
  out:
+  scratch_buffer_free (&needed_space);
+
   if (errno == 0 && errno_saved != 0)
     __set_errno (errno_saved);
 

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=ca21a2d58fc486434ee472fc9e70486e6a258c3f

commit ca21a2d58fc486434ee472fc9e70486e6a258c3f
Author: Florian Weimer <fweimer@redhat.com>
Date:   Sun Mar 1 15:14:19 2015 +0100

    getgrent_next_nss (compat-initgroups): Remove alloca fallback
    
    If the caller-supplied buffer is not large enough, fall back directly
    malloc.
    
    The previous __libc_use_alloca check was incorrect because it did not
    take into account that extend_alloca may fail to merge allocations, so
    it would underestimate the stack space being used by roughly a factor
    of two.
    
    	[BZ #18023]
    	* nis/nss_compat/compat-initgroups.c (getgrent_next_nss): Fall
    	back to malloc directly, without stack allocations.

diff --git a/nis/nss_compat/compat-initgroups.c b/nis/nss_compat/compat-initgroups.c
index e65b10f..4843e5c 100644
--- a/nis/nss_compat/compat-initgroups.c
+++ b/nis/nss_compat/compat-initgroups.c
@@ -310,7 +310,6 @@ getgrent_next_nss (ent_t *ent, char *buffer, size_t buflen, const char *user,
 		 overwrite the pointer with one to a bigger buffer.  */
 	      char *tmpbuf = buffer;
 	      size_t tmplen = buflen;
-	      bool use_malloc = false;
 
 	      for (int i = 0; i < mystart; i++)
 		{
@@ -319,29 +318,26 @@ getgrent_next_nss (ent_t *ent, char *buffer, size_t buflen, const char *user,
 			 == NSS_STATUS_TRYAGAIN
 			 && *errnop == ERANGE)
                     {
-                      if (__libc_use_alloca (tmplen * 2))
-                        {
-                          if (tmpbuf == buffer)
-                            {
-                              tmplen *= 2;
-                              tmpbuf = __alloca (tmplen);
-                            }
-                          else
-                            tmpbuf = extend_alloca (tmpbuf, tmplen, tmplen * 2);
-                        }
-                      else
-                        {
-                          tmplen *= 2;
-                          char *newbuf = realloc (use_malloc ? tmpbuf : NULL, tmplen);
-
-                          if (newbuf == NULL)
-                            {
-                              status = NSS_STATUS_TRYAGAIN;
-			      goto done;
-                            }
-                          use_malloc = true;
-                          tmpbuf = newbuf;
-                        }
+		      /* Check for overflow. */
+		      if (__glibc_unlikely (tmplen * 2 < tmplen))
+			{
+			  __set_errno (ENOMEM);
+			  status = NSS_STATUS_TRYAGAIN;
+			  goto done;
+			}
+		      /* Increase the size.  Make sure that we retry
+			 with a reasonable size.  */
+		      tmplen *= 2;
+		      if (tmplen < 1024)
+			tmplen = 1024;
+		      if (tmpbuf != buffer)
+			free (tmpbuf);
+		      tmpbuf = malloc (tmplen);
+		      if (__glibc_unlikely (tmpbuf == NULL))
+			{
+			  status = NSS_STATUS_TRYAGAIN;
+			  goto done;
+			}
                     }
 
 		  if (__builtin_expect  (status != NSS_STATUS_NOTFOUND, 1))
@@ -369,7 +365,7 @@ getgrent_next_nss (ent_t *ent, char *buffer, size_t buflen, const char *user,
 	      status = NSS_STATUS_NOTFOUND;
 
  done:
-	      if (use_malloc)
+	      if (tmpbuf != buffer)
 	        free (tmpbuf);
 	    }
 

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=8f0601236753cf4fa211f533b3bc9143b3ac9129

commit 8f0601236753cf4fa211f533b3bc9143b3ac9129
Author: Florian Weimer <fweimer@redhat.com>
Date:   Sun Mar 1 18:29:47 2015 +0100

    nscd restart: Use malloc instead of extend_alloca
    
    This introduces a separate function, read_cmdline, which reads the
    contents of /proc/self/cmdline into a heap-allocated buffer.
    
    	[BZ #18023]
    	* nscd/connections.c (read_cmdline): New function.
    	(restart): Use it.  Update comment.

diff --git a/nscd/connections.c b/nscd/connections.c
index f3b16f7..4e96e49 100644
--- a/nscd/connections.c
+++ b/nscd/connections.c
@@ -1353,64 +1353,83 @@ request from '%s' [%ld] not handled due to missing permission"),
     }
 }
 
-
-/* Restart the process.  */
-static void
-restart (void)
+static char *
+read_cmdline (size_t *size)
 {
-  /* First determine the parameters.  We do not use the parameters
-     passed to main() since in case nscd is started by running the
-     dynamic linker this will not work.  Yes, this is not the usual
-     case but nscd is part of glibc and we occasionally do this.  */
-  size_t buflen = 1024;
-  char *buf = alloca (buflen);
-  size_t readlen = 0;
   int fd = open ("/proc/self/cmdline", O_RDONLY);
-  if (fd == -1)
+  if (fd < 0)
+    return NULL;
+  size_t current = 0;
+  size_t limit = 1024;
+  char *buffer = malloc (limit);
+  if (buffer == NULL)
     {
-      dbg_log (_("\
-cannot open /proc/self/cmdline: %s; disabling paranoia mode"),
-	       strerror (errno));
-
-      paranoia = 0;
-      return;
+      close (fd);
+      errno = ENOMEM;
+      return NULL;
     }
-
   while (1)
     {
-      ssize_t n = TEMP_FAILURE_RETRY (read (fd, buf + readlen,
-					    buflen - readlen));
-      if (n == -1)
+      if (current == limit)
 	{
-	  dbg_log (_("\
-cannot read /proc/self/cmdline: %s; disabling paranoia mode"),
-		   strerror (errno));
+	  char *newptr;
+	  if (2 * limit < limit
+	      || (newptr = realloc (buffer, 2 * limit)) == NULL)
+	    {
+	      free (buffer);
+	      close (fd);
+	      errno = ENOMEM;
+	      return NULL;
+	    }
+	  buffer = newptr;
+	  limit *= 2;
+	}
 
+      ssize_t n = TEMP_FAILURE_RETRY (read (fd, buffer + current,
+					    limit - current));
+      if (n == -1)
+	{
+	  int e = errno;
+	  free (buffer);
 	  close (fd);
-	  paranoia = 0;
-	  return;
+	  errno = e;
+	  return NULL;
 	}
-
-      readlen += n;
-
-      if (readlen < buflen)
+      if (n == 0)
 	break;
-
-      /* We might have to extend the buffer.  */
-      size_t old_buflen = buflen;
-      char *newp = extend_alloca (buf, buflen, 2 * buflen);
-      buf = memmove (newp, buf, old_buflen);
+      current += n;
     }
 
   close (fd);
+  *size = current;
+  return buffer;
+}
+
+
+/* Restart the process.  */
+static void
+restart (void)
+{
+  /* First determine the parameters.  We do not use the parameters
+     passed to main() because then nscd would would use the system
+     libc after restarting even if it was started by a non-system
+     dynamic linker during glibc testing.  */
+  size_t readlen;
+  char *cmdline = read_cmdline (&readlen);
+  if (cmdline == NULL)
+    {
+      dbg_log (_("\
+cannot open /proc/self/cmdline: %m; disabling paranoia mode"));
+      paranoia = 0;
+      return;
+    }
 
   /* Parse the command line.  Worst case scenario: every two
      characters form one parameter (one character plus NUL).  */
   char **argv = alloca ((readlen / 2 + 1) * sizeof (argv[0]));
   int argc = 0;
 
-  char *cp = buf;
-  while (cp < buf + readlen)
+  for (char *cp = cmdline; cp < cmdline + readlen;)
     {
       argv[argc++] = cp;
       cp = (char *) rawmemchr (cp, '\0') + 1;
@@ -1427,6 +1446,7 @@ cannot change to old UID: %s; disabling paranoia mode"),
 		   strerror (errno));
 
 	  paranoia = 0;
+	  free (cmdline);
 	  return;
 	}
 
@@ -1438,6 +1458,7 @@ cannot change to old GID: %s; disabling paranoia mode"),
 
 	  ignore_value (setuid (server_uid));
 	  paranoia = 0;
+	  free (cmdline);
 	  return;
 	}
     }
@@ -1455,6 +1476,7 @@ cannot change to old working directory: %s; disabling paranoia mode"),
 	  ignore_value (setgid (server_gid));
 	}
       paranoia = 0;
+      free (cmdline);
       return;
     }
 
@@ -1503,6 +1525,7 @@ cannot change to old working directory: %s; disabling paranoia mode"),
     dbg_log (_("cannot change current working directory to \"/\": %s"),
 	     strerror (errno));
   paranoia = 0;
+  free (cmdline);
 
   /* Reenable the databases.  */
   time_t now = time (NULL);

-----------------------------------------------------------------------


hooks/post-receive
-- 
GNU C Library master sources


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]