9fce074
From the upstream branch fw/extend_alloca.
9fce074
9fce074
commit dc79f9aa56933dc8b475209f9a4059965b50ea26
9fce074
Author: Florian Weimer <fweimer@redhat.com>
9fce074
Date:   Sun Mar 1 18:29:47 2015 +0100
9fce074
9fce074
    nscd restart: Use malloc instead of extend_alloca
9fce074
    
9fce074
    This introduces a separate function, read_cmdline, which reads the
9fce074
    contents of /proc/self/cmdline into a heap-allocated buffer.
9fce074
    
9fce074
    	[BZ #18023]
9fce074
    	* nscd/connections.c (read_cmdline): New function.
9fce074
    	(restart): Use it.  Update comment.
9fce074
9fce074
commit 9bed8b7fca7867d3027b66ce3985a75136aed013
9fce074
Author: Florian Weimer <fweimer@redhat.com>
9fce074
Date:   Sun Mar 1 15:14:19 2015 +0100
9fce074
9fce074
    getgrent_next_nss (compat-initgroups): Remove alloca fallback
9fce074
    
9fce074
    If the caller-supplied buffer is not large enough, fall back directly
9fce074
    malloc.
9fce074
    
9fce074
    The previous __libc_use_alloca check was incorrect because it did not
9fce074
    take into account that extend_alloca may fail to merge allocations, so
9fce074
    it would underestimate the stack space being used by roughly a factor
9fce074
    of two.
9fce074
    
9fce074
    	[BZ #18023]
9fce074
    	* nis/nss_compat/compat-initgroups.c (getgrent_next_nss): Fall
9fce074
    	back to malloc directly, without stack allocations.
9fce074
9fce074
commit c95cc759ecb21f812872934ac55518aef28cf46b
9fce074
Author: Florian Weimer <fweimer@redhat.com>
9fce074
Date:   Sun Mar 1 16:03:01 2015 +0100
9fce074
9fce074
    _dl_map_object_deps: Use struct scratch_buffer instead of extend_alloca
9fce074
    
9fce074
    The function comment suggests that _dl_map_object_deps cannot use
9fce074
    malloc, but it already allocates the l_initfini array on the heap, so
9fce074
    the additional allocation should be acceptable.
9fce074
    
9fce074
    	[BZ #18023]
9fce074
    	* elf/dl-deps.c (_dl_map_object_deps): Use struct
9fce074
    	scratch_buffer instead of extend_alloca.
9fce074
9fce074
commit e38bff4db6f03d1fab732737f43a25160c3e4703
9fce074
Author: Florian Weimer <fweimer@redhat.com>
9fce074
Date:   Sun Mar 1 16:18:21 2015 +0100
9fce074
9fce074
    _nss_nis_initgroups_dyn: Use struct scratch_buffer instead of extend_alloca
9fce074
    
9fce074
    Also adjusts the internal function get_uid.
9fce074
    
9fce074
    	[BZ #18023]
9fce074
            * nis/nss_nis/nis-initgroups.c (get_uid, _nss_nis_initgroups_dyn):
9fce074
    	Use struct scratch_buffer instead of extend_alloca.
9fce074
9fce074
commit 8825d4709a686a870d313cc602d489ddd5354a08
9fce074
Author: Florian Weimer <fweimer@redhat.com>
9fce074
Date:   Sun Mar 1 18:55:33 2015 +0100
9fce074
9fce074
    nscd: Use struct scratch_buffer instead of extend_alloca in most caches
9fce074
    
9fce074
    This replaces the ERANGE retry loops with loops which have heap
9fce074
    fallback.  Heap allocation might actually be required for extremely
9fce074
    large NSS results.
9fce074
    
9fce074
    	[BZ #18023]
9fce074
    	* nscd/grpcache.c (addgrbyX): Use struct scratch_buffer instead
9fce074
    	of extend_alloca.
9fce074
    	* nscd/hstcache.c (addhstbyX): Likewise.
9fce074
    	* nscd/pwdcache.c (addpwbyX): Likewise.
9fce074
    	* nscd/servicescache.c (addservbyX): Likewise.
9fce074
9fce074
commit 140d8711d446f5193b04b56e714ddf8d0eddbf62
9fce074
Author: Florian Weimer <fweimer@redhat.com>
9fce074
Date:   Sun Mar 1 18:59:48 2015 +0100
9fce074
9fce074
    nscd: Switch to struct scratch_buffer in adhstaiX
9fce074
    
9fce074
    The pre-allocation of the three scratch buffers increased the initial
9fce074
    stack size somewhat, but if retries are needed, the previous version
9fce074
    used more stack space if extend_alloca could not merge allocations.
9fce074
    Lack of alloca accounting also means could be problematic with
9fce074
    extremely large NSS responses, too.
9fce074
    
9fce074
    	[BZ #18023]
9fce074
    	* nscd/aicache.c (addhstaiX): Use struct scratch_buffer instead
9fce074
    	of extend_alloca.
9fce074
9fce074
commit 1af14faef808f03276766e5ee6d9ee7dc9053fba
9fce074
Author: Florian Weimer <fweimer@redhat.com>
9fce074
Date:   Sun Mar 1 19:03:01 2015 +0100
9fce074
9fce074
    getent: Switch to struct scratch_buffer in initgroups_keys
9fce074
    
9fce074
    The retry loop is slightly different here because getgrouplist
9fce074
    provides size information, so scratch_buffer_set_array_size can be
9fce074
    used to grow the buffer in a more precise fashion.
9fce074
    
9fce074
    	[BZ #18023]
9fce074
    	* nss/getent.c (initgroups_keys): Use struct scratch_buffer
9fce074
    	instead of extend_alloca.
9fce074
9fce074
commit 9b71d3b4df6dd4e49f7638d1d936c921c50fa3d9
9fce074
Author: Florian Weimer <fweimer@redhat.com>
9fce074
Date:   Sun Mar 1 19:09:00 2015 +0100
9fce074
9fce074
    nss_files: Use struct scratch_buffer instead of extend_alloca
9fce074
    
9fce074
    In both _nss_files_gethostbyname3_r and _nss_files_initgroups_dyn,
9fce074
    __libc_use_alloca was misused because it was not taken into account
9fce074
    that extend_alloca can fail to merge allocations.
9fce074
    
9fce074
    	[BZ #18023]
9fce074
    	* nss/nss_files/files-hosts.c (_nss_files_gethostbyname3_r):
9fce074
    	Use struct scratch_buffer instead of extend_alloca.
9fce074
    	* nss/nss_files/files-initgroups.c (_nss_files_initgroups_dyn):
9fce074
    	Likewise.
9fce074
9fce074
commit 11c2a8bad9ca5fe510b73c0204b3dcf703f14d5c
9fce074
Author: Florian Weimer <fweimer@redhat.com>
9fce074
Date:   Sun Mar 1 19:11:55 2015 +0100
9fce074
9fce074
    gethostid (Linux variant): Switch to struct scratch_buffer
9fce074
    
9fce074
    Previously, extend_alloca was used without alloca accounting,
9fce074
    which could have been problematic with large NSS results.
9fce074
    
9fce074
    	[BZ #18023]
9fce074
    	* sysdeps/unix/sysv/linux/gethostid.c (gethostid): Use struct
9fce074
    	scratch_buffer instead of extend_alloca.
9fce074
9fce074
commit 6de00dd8a3a76d0b7586393451e65ad6c2721a71
9fce074
Author: Florian Weimer <fweimer@redhat.com>
9fce074
Date:   Sun Mar 1 19:14:29 2015 +0100
9fce074
9fce074
    getlogin_r (Linux variant): Switch to struct scratch_buffer
9fce074
    
9fce074
    This corrects the alloca accounting as a side effect.  It was not off
9fce074
    if extend_alloca failed to merge allocations.
9fce074
    
9fce074
    	[BZ #18023]
9fce074
    	* sysdeps/unix/sysv/linux/getlogin_r.c (__getlogin_r_loginuid):
9fce074
    	Use struct scratch_buffer instead of extend_alloca.
9fce074
9fce074
commit 488063238ee5c87b66c6982b1b6d508e30e44386
9fce074
Author: Florian Weimer <fweimer@redhat.com>
9fce074
Date:   Sun Mar 1 19:48:31 2015 +0100
9fce074
9fce074
    wordexp: Rewrite parse_tilde to use struct scratch_buffer
9fce074
    
9fce074
    	[BZ #18023]
9fce074
    	* posix/wordexp.c (parse_tilde): Use struct scratch_buffer
9fce074
    	instead of extend_alloca.
9fce074
9fce074
commit 683543bbb3e2c1b17554c4096d00c2980f39a802
9fce074
Author: Florian Weimer <fweimer@redhat.com>
9fce074
Date:   Sun Mar 1 23:22:45 2015 +0100
9fce074
9fce074
    Remove macros extend_alloca, extend_alloca_account [BZ #18023]
9fce074
    
9fce074
    And also the helper macro stackinfo_alloca_round.
9fce074
    
9fce074
    extend_alloca simply does not work on x86_64 and current i386 because
9fce074
    its peculiar stack alignment rules.
9fce074
    
9fce074
    Here's an analysis of the _dl_fini situation (before the removal of
9fce074
    extend_alloca).
9fce074
    
9fce074
    Dump of assembler code for function _dl_fini:
9fce074
    <+0>:	push   %rbp
9fce074
    <+1>:	mov    %rsp,%rbp
9fce074
    <+4>:	push   %r15
9fce074
    <+6>:	push   %r14
9fce074
    <+8>:	push   %r13
9fce074
    <+10>:	push   %r12
9fce074
    <+12>:	push   %rbx
9fce074
    <+13>:	sub    $0x38,%rsp
9fce074
    
9fce074
    The function pushes 6 registers on the stack and allocates 0x38 bytes,
9fce074
    which means that %rsp is a multiple of 16 after function prologue.
9fce074
    
9fce074
    The initial alloca allocation does not change %rsp alignment:
9fce074
    
9fce074
    <+210>:	shr    $0x4,%rcx
9fce074
    <+214>:	shl    $0x4,%rcx
9fce074
    <+218>:	sub    %rcx,%rsp
9fce074
    
9fce074
    %r15 is the address of the previous stack allocation, it is used below.
9fce074
    
9fce074
    This is the extend_alloca reallocation branch:
9fce074
    
9fce074
    <+734>:	add    $0xf,%rdx
9fce074
    <+738>:	and    $0xfffffffffffffff0,%rdx
9fce074
    <+742>:	lea    0x1e(%rdx),%rcx
9fce074
    <+746>:	shr    $0x4,%rcx
9fce074
    <+750>:	shl    $0x4,%rcx
9fce074
    <+754>:	sub    %rcx,%rsp
9fce074
    <+757>:	lea    0xf(%rsp),%rcx
9fce074
    <+762>:	and    $0xfffffffffffffff0,%rcx
9fce074
    <+766>:	lea    (%rcx,%rdx,1),%rsi
9fce074
    <+770>:	cmp    %rsi,%r15
9fce074
    <+773>:	je     0x7f963940b673 <_dl_fini+787>
9fce074
    <+775>:	mov    %rdx,-0x58(%rbp)
9fce074
    <+787>:	add    %rdx,-0x58(%rbp)
9fce074
    
9fce074
    (a) %rdx, the new requested size, is rounded up to a multiple of 16
9fce074
    (+734, %+738), and the result is stored in %rdx@738.
9fce074
    
9fce074
    (b) %rdx@738 + 31 is rounded down to a multiple of 16, the result is
9fce074
    stored in rcx@750 (+742, +746, +750).  So %rcx@750 == %rdx@738 + 16.
9fce074
    
9fce074
    (c) %rcx@750 bytes are allocated on the stack (+754).  %rsp is rounded
9fce074
    upwards to a multiple of 16, result is stored in %rcx@762 (+757, +762).
9fce074
    This does not change the value of %rsp because it already was a multiple
9fce074
    of 16.
9fce074
    
9fce074
    (d) %rsi@766 == %rcx@762 + %rdx@738 is compared against %r15.  But this
9fce074
    comparison is always false because we allocated 16 extra bytes on the
9fce074
    stack in (b), which were reserved for the alignment in (c), but in fact
9fce074
    unused.  We are left with a gap in stack usage, and the comparison is
9fce074
    always false.
9fce074
    
9fce074
    (@XXX refers to register values after executing the instruction at
9fce074
    offset +XXX.)
9fce074
    
9fce074
    If the alignment gap was actually used because of different alignment
9fce074
    for %rsp, then the comparison failure would still occur because the gap
9fce074
    would not have been added after this reallocation, but before the
9fce074
    previous allocation.
9fce074
    
9fce074
    As a result, extend_alloca is never able to merge allocations.  It also
9fce074
    turns out that the interface is difficult to use, especially in
9fce074
    cojunction with alloca account (which is rarely optional).
9fce074
    
9fce074
    	[BZ #18023]
9fce074
    	* include/alloca.h (stackinfo_alloca_round, extend_alloca,
9fce074
    	extend_alloca_account): Remove.
ab21010
ab21010
diff --git a/elf/dl-deps.c b/elf/dl-deps.c
ab21010
index 1b8bac65932a7713..bc59f0ff7b4d7c61 100644
9fce074
--- a/elf/dl-deps.c
9fce074
+++ b/elf/dl-deps.c
9fce074
@@ -27,6 +27,7 @@
9fce074
 #include <unistd.h>
9fce074
 #include <sys/param.h>
9fce074
 #include <ldsodefs.h>
9fce074
+#include <scratch_buffer.h>
9fce074
 
9fce074
 #include <dl-dst.h>
9fce074
 
ab21010
@@ -184,9 +185,8 @@ _dl_map_object_deps (struct link_map *map,
9fce074
   /* Pointer to last unique object.  */
9fce074
   tail = &known[nlist - 1];
9fce074
 
9fce074
-  /* No alloca'd space yet.  */
9fce074
-  struct link_map **needed_space = NULL;
9fce074
-  size_t needed_space_bytes = 0;
9fce074
+  struct scratch_buffer needed_space;
9fce074
+  scratch_buffer_init (&needed_space);
9fce074
 
9fce074
   /* Process each element of the search list, loading each of its
9fce074
      auxiliary objects and immediate dependencies.  Auxiliary objects
ab21010
@@ -217,13 +217,12 @@ _dl_map_object_deps (struct link_map *map,
9fce074
       if (l->l_searchlist.r_list == NULL && l->l_initfini == NULL
9fce074
 	  && l != map && l->l_ldnum > 0)
9fce074
 	{
9fce074
-	  size_t new_size = l->l_ldnum * sizeof (struct link_map *);
9fce074
-
9fce074
-	  if (new_size > needed_space_bytes)
9fce074
-	    needed_space
9fce074
-	      = extend_alloca (needed_space, needed_space_bytes, new_size);
9fce074
-
9fce074
-	  needed = needed_space;
9fce074
+	  /* l->l_ldnum includes space for the terminating NULL.  */
9fce074
+	  if (!scratch_buffer_set_array_size
9fce074
+	      (&needed_space, l->l_ldnum, sizeof (struct link_map *)))
9fce074
+	    _dl_signal_error (ENOMEM, map->l_name, NULL,
9fce074
+			      N_("cannot allocate dependency buffer"));
9fce074
+	  needed = needed_space.data;
9fce074
 	}
9fce074
 
9fce074
       if (l->l_info[DT_NEEDED] || l->l_info[AUXTAG] || l->l_info[FILTERTAG])
ab21010
@@ -463,8 +462,11 @@ _dl_map_object_deps (struct link_map *map,
9fce074
 	  struct link_map **l_initfini = (struct link_map **)
9fce074
 	    malloc ((2 * nneeded + 1) * sizeof needed[0]);
9fce074
 	  if (l_initfini == NULL)
9fce074
-	    _dl_signal_error (ENOMEM, map->l_name, NULL,
9fce074
-			      N_("cannot allocate dependency list"));
9fce074
+	    {
9fce074
+	      scratch_buffer_free (&needed_space);
9fce074
+	      _dl_signal_error (ENOMEM, map->l_name, NULL,
9fce074
+				N_("cannot allocate dependency list"));
9fce074
+	    }
9fce074
 	  l_initfini[0] = l;
9fce074
 	  memcpy (&l_initfini[1], needed, nneeded * sizeof needed[0]);
9fce074
 	  memcpy (&l_initfini[nneeded + 1], l_initfini,
ab21010
@@ -482,6 +484,8 @@ _dl_map_object_deps (struct link_map *map,
9fce074
     }
9fce074
 
9fce074
  out:
9fce074
+  scratch_buffer_free (&needed_space);
9fce074
+
9fce074
   if (errno == 0 && errno_saved != 0)
9fce074
     __set_errno (errno_saved);
9fce074
 
ab21010
diff --git a/include/alloca.h b/include/alloca.h
ab21010
index fd90664f0a17cd6d..c0b83954436ed4c1 100644
9fce074
--- a/include/alloca.h
9fce074
+++ b/include/alloca.h
0b05408
@@ -23,57 +23,17 @@ libc_hidden_proto (__libc_alloca_cutoff)
9fce074
 
9fce074
 #include <allocalim.h>
9fce074
 
9fce074
-#ifndef stackinfo_alloca_round
9fce074
-# define stackinfo_alloca_round(l) (((l) + 15) & -16)
9fce074
-#endif
9fce074
-
9fce074
-#if _STACK_GROWS_DOWN
9fce074
-# define extend_alloca(buf, len, newlen) \
9fce074
-  (__typeof (buf)) ({ size_t __newlen = stackinfo_alloca_round (newlen);      \
9fce074
-		      char *__newbuf = __alloca (__newlen);		      \
9fce074
-		      if (__newbuf + __newlen == (char *) (buf))	      \
9fce074
-			len += __newlen;				      \
9fce074
-		      else						      \
9fce074
-			len = __newlen;					      \
9fce074
-		      __newbuf; })
9fce074
-#elif _STACK_GROWS_UP
9fce074
-# define extend_alloca(buf, len, newlen) \
9fce074
-  (__typeof (buf)) ({ size_t __newlen = stackinfo_alloca_round (newlen);      \
9fce074
-		      char *__newbuf = __alloca (__newlen);		      \
9fce074
-		      char *__buf = (char *) (buf);			      \
9fce074
-		      if (__buf + len == __newbuf)			      \
9fce074
-			{						      \
9fce074
-			  len += __newlen;				      \
9fce074
-			  __newbuf = __buf;				      \
9fce074
-			}						      \
9fce074
-		      else						      \
9fce074
-			len = __newlen;					      \
9fce074
-		      __newbuf; })
9fce074
-#else
9fce074
-# define extend_alloca(buf, len, newlen) \
9fce074
-  __alloca (((len) = (newlen)))
9fce074
-#endif
9fce074
-
9fce074
 #if defined stackinfo_get_sp && defined stackinfo_sub_sp
9fce074
 # define alloca_account(size, avar) \
9fce074
   ({ void *old__ = stackinfo_get_sp ();					      \
9fce074
      void *m__ = __alloca (size);					      \
9fce074
      avar += stackinfo_sub_sp (old__);					      \
9fce074
      m__; })
9fce074
-# define extend_alloca_account(buf, len, newlen, avar) \
9fce074
-  ({ void *old__ = stackinfo_get_sp ();					      \
9fce074
-     void *m__ = extend_alloca (buf, len, newlen);			      \
9fce074
-     avar += stackinfo_sub_sp (old__);					      \
9fce074
-     m__; })
9fce074
 #else
9fce074
 # define alloca_account(size, avar) \
9fce074
   ({ size_t s__ = (size);						      \
9fce074
      avar += s__;							      \
9fce074
      __alloca (s__); })
9fce074
-# define extend_alloca_account(buf, len, newlen, avar) \
9fce074
-  ({ size_t s__ = (newlen);						      \
9fce074
-     avar += s__;							      \
9fce074
-     extend_alloca (buf, len, s__); })
9fce074
 #endif
9fce074
 
0b05408
 # endif /* !_ISOMAC */
ab21010
diff --git a/nis/nss_compat/compat-initgroups.c b/nis/nss_compat/compat-initgroups.c
ab21010
index 1b37e0c295f481df..cc3db7889ba289db 100644
9fce074
--- a/nis/nss_compat/compat-initgroups.c
9fce074
+++ b/nis/nss_compat/compat-initgroups.c
ab21010
@@ -310,7 +310,6 @@ getgrent_next_nss (ent_t *ent, char *buffer, size_t buflen, const char *user,
9fce074
 		 overwrite the pointer with one to a bigger buffer.  */
9fce074
 	      char *tmpbuf = buffer;
9fce074
 	      size_t tmplen = buflen;
9fce074
-	      bool use_malloc = false;
9fce074
 
9fce074
 	      for (int i = 0; i < mystart; i++)
9fce074
 		{
ab21010
@@ -319,29 +318,26 @@ getgrent_next_nss (ent_t *ent, char *buffer, size_t buflen, const char *user,
9fce074
 			 == NSS_STATUS_TRYAGAIN
9fce074
 			 && *errnop == ERANGE)
9fce074
                     {
9fce074
-                      if (__libc_use_alloca (tmplen * 2))
9fce074
-                        {
9fce074
-                          if (tmpbuf == buffer)
9fce074
-                            {
9fce074
-                              tmplen *= 2;
9fce074
-                              tmpbuf = __alloca (tmplen);
9fce074
-                            }
9fce074
-                          else
9fce074
-                            tmpbuf = extend_alloca (tmpbuf, tmplen, tmplen * 2);
9fce074
-                        }
9fce074
-                      else
9fce074
-                        {
9fce074
-                          tmplen *= 2;
9fce074
-                          char *newbuf = realloc (use_malloc ? tmpbuf : NULL, tmplen);
9fce074
-
9fce074
-                          if (newbuf == NULL)
9fce074
-                            {
9fce074
-                              status = NSS_STATUS_TRYAGAIN;
9fce074
-			      goto done;
9fce074
-                            }
9fce074
-                          use_malloc = true;
9fce074
-                          tmpbuf = newbuf;
9fce074
-                        }
9fce074
+		      /* Check for overflow. */
9fce074
+		      if (__glibc_unlikely (tmplen * 2 < tmplen))
9fce074
+			{
9fce074
+			  __set_errno (ENOMEM);
9fce074
+			  status = NSS_STATUS_TRYAGAIN;
9fce074
+			  goto done;
9fce074
+			}
9fce074
+		      /* Increase the size.  Make sure that we retry
9fce074
+			 with a reasonable size.  */
9fce074
+		      tmplen *= 2;
9fce074
+		      if (tmplen < 1024)
9fce074
+			tmplen = 1024;
9fce074
+		      if (tmpbuf != buffer)
9fce074
+			free (tmpbuf);
9fce074
+		      tmpbuf = malloc (tmplen);
9fce074
+		      if (__glibc_unlikely (tmpbuf == NULL))
9fce074
+			{
9fce074
+			  status = NSS_STATUS_TRYAGAIN;
9fce074
+			  goto done;
9fce074
+			}
9fce074
                     }
9fce074
 
9fce074
 		  if (__builtin_expect  (status != NSS_STATUS_NOTFOUND, 1))
ab21010
@@ -369,7 +365,7 @@ getgrent_next_nss (ent_t *ent, char *buffer, size_t buflen, const char *user,
9fce074
 	      status = NSS_STATUS_NOTFOUND;
9fce074
 
9fce074
  done:
9fce074
-	      if (use_malloc)
9fce074
+	      if (tmpbuf != buffer)
9fce074
 	        free (tmpbuf);
9fce074
 	    }
9fce074
 
ab21010
diff --git a/nis/nss_nis/nis-initgroups.c b/nis/nss_nis/nis-initgroups.c
ab21010
index 3784c101f7ee31aa..c872b32e15f55e3d 100644
9fce074
--- a/nis/nss_nis/nis-initgroups.c
9fce074
+++ b/nis/nss_nis/nis-initgroups.c
9fce074
@@ -16,7 +16,6 @@
9fce074
    License along with the GNU C Library; if not, see
9fce074
    <http://www.gnu.org/licenses/>.  */
9fce074
 
9fce074
-#include <alloca.h>
9fce074
 #include <ctype.h>
9fce074
 #include <errno.h>
9fce074
 #include <grp.h>
9fce074
@@ -27,6 +26,7 @@
9fce074
 #include <rpcsvc/yp.h>
9fce074
 #include <rpcsvc/ypclnt.h>
9fce074
 #include <sys/param.h>
9fce074
+#include <scratch_buffer.h>
9fce074
 
9fce074
 #include "nss-nis.h"
9fce074
 #include <libnsl.h>
ab21010
@@ -120,27 +120,30 @@ internal_getgrent_r (struct group *grp, char *buffer, size_t buflen,
9fce074
 static int
9fce074
 get_uid (const char *user, uid_t *uidp)
9fce074
 {
9fce074
-  size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX);
9fce074
-  char *buf = (char *) alloca (buflen);
9fce074
+  struct scratch_buffer tmpbuf;
9fce074
+  scratch_buffer_init (&tmpbuf);
9fce074
 
9fce074
   while (1)
9fce074
     {
9fce074
       struct passwd result;
9fce074
       struct passwd *resp;
9fce074
 
9fce074
-      int r = getpwnam_r (user, &result, buf, buflen, &resp);
9fce074
+      int r = getpwnam_r (user, &result, tmpbuf.data, tmpbuf.length, &resp);
9fce074
       if (r == 0 && resp != NULL)
9fce074
 	{
9fce074
 	  *uidp = resp->pw_uid;
9fce074
+	  scratch_buffer_free (&tmpbuf);
9fce074
 	  return 0;
9fce074
 	}
9fce074
 
9fce074
       if (r != ERANGE)
9fce074
 	break;
9fce074
 
9fce074
-      buf = extend_alloca (buf, buflen, 2 * buflen);
9fce074
+      if (!scratch_buffer_grow (&tmpbuf))
9fce074
+	return 1;
9fce074
     }
9fce074
 
9fce074
+  scratch_buffer_free (&tmpbuf);
9fce074
   return 1;
9fce074
 }
9fce074
 
ab21010
@@ -254,8 +257,6 @@ _nss_nis_initgroups_dyn (const char *user, gid_t group, long int *start,
9fce074
     }
9fce074
 
9fce074
   struct group grpbuf, *g;
9fce074
-  size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX);
9fce074
-  char *tmpbuf;
9fce074
   enum nss_status status;
9fce074
   intern_t intern = { NULL, NULL, 0 };
9fce074
   gid_t *groups = *groupsp;
ab21010
@@ -264,15 +265,21 @@ _nss_nis_initgroups_dyn (const char *user, gid_t group, long int *start,
9fce074
   if (status != NSS_STATUS_SUCCESS)
9fce074
     return status;
9fce074
 
9fce074
-  tmpbuf = __alloca (buflen);
9fce074
+  struct scratch_buffer tmpbuf;
9fce074
+  scratch_buffer_init (&tmpbuf);
9fce074
 
0f28e75
   while (1)
9fce074
     {
9fce074
       while ((status =
9fce074
-	      internal_getgrent_r (&grpbuf, tmpbuf, buflen, errnop,
9fce074
+	      internal_getgrent_r (&grpbuf, tmpbuf.data, tmpbuf.length, errnop,
9fce074
 				   &intern)) == NSS_STATUS_TRYAGAIN
9fce074
              && *errnop == ERANGE)
9fce074
-	tmpbuf = extend_alloca (tmpbuf, buflen, 2 * buflen);
9fce074
+	if (!scratch_buffer_grow (&tmpbuf))
9fce074
+	  {
9fce074
+	    status = NSS_STATUS_TRYAGAIN;
0f28e75
+	    *errnop = errno;
9fce074
+	    goto done;
9fce074
+	  }
9fce074
 
9fce074
       if (status != NSS_STATUS_SUCCESS)
0f28e75
 	{
0f28e75
@@ -331,6 +338,7 @@ done:
9fce074
       intern.start = intern.start->next;
9fce074
       free (intern.next);
9fce074
     }
9fce074
+  scratch_buffer_free (&tmpbuf);
9fce074
 
9fce074
   return status;
9fce074
 }
ab21010
diff --git a/nscd/aicache.c b/nscd/aicache.c
ab21010
index 7bf4131979451040..ea29b1c3d99bb530 100644
9fce074
--- a/nscd/aicache.c
9fce074
+++ b/nscd/aicache.c
c659285
@@ -27,6 +27,7 @@
9fce074
 #include <sys/mman.h>
c659285
 #include <resolv/resolv-internal.h>
9fce074
 #include <resolv/res_hconf.h>
9fce074
+#include <scratch_buffer.h>
9fce074
 
9fce074
 #include "dbg_log.h"
9fce074
 #include "nscd.h"
ab21010
@@ -113,10 +114,13 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
9fce074
   int old_res_options = _res.options;
c659285
   _res.options &= ~DEPRECATED_RES_USE_INET6;
9fce074
 
9fce074
-  size_t tmpbuf6len = 1024;
9fce074
-  char *tmpbuf6 = alloca (tmpbuf6len);
9fce074
-  size_t tmpbuf4len = 0;
9fce074
-  char *tmpbuf4 = NULL;
9fce074
+  struct scratch_buffer tmpbuf6;
9fce074
+  scratch_buffer_init (&tmpbuf6);
9fce074
+  struct scratch_buffer tmpbuf4;
9fce074
+  scratch_buffer_init (&tmpbuf4);
9fce074
+  struct scratch_buffer canonbuf;
9fce074
+  scratch_buffer_init (&canonbuf);
9fce074
+
9fce074
   int32_t ttl = INT32_MAX;
9fce074
   ssize_t total = 0;
9fce074
   char *key_copy = NULL;
ab21010
@@ -129,6 +133,7 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
9fce074
       int status[2] = { NSS_STATUS_UNAVAIL, NSS_STATUS_UNAVAIL };
9fce074
       int naddrs = 0;
9fce074
       size_t addrslen = 0;
9fce074
+
9fce074
       char *canon = NULL;
9fce074
       size_t canonlen;
9fce074
 
ab21010
@@ -143,12 +148,17 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
9fce074
 	      at = &atmem;
9fce074
 	      rc6 = 0;
9fce074
 	      herrno = 0;
9fce074
-	      status[1] = DL_CALL_FCT (fct4, (key, &at, tmpbuf6, tmpbuf6len,
9fce074
+	      status[1] = DL_CALL_FCT (fct4, (key, &at,
9fce074
+					      tmpbuf6.data, tmpbuf6.length,
9fce074
 					      &rc6, &herrno, &ttl));
9fce074
 	      if (rc6 != ERANGE || (herrno != NETDB_INTERNAL
9fce074
 				    && herrno != TRY_AGAIN))
9fce074
 		break;
9fce074
-	      tmpbuf6 = extend_alloca (tmpbuf6, tmpbuf6len, 2 * tmpbuf6len);
9fce074
+	      if (!scratch_buffer_grow (&tmpbuf6))
9fce074
+		{
9fce074
+		  rc6 = ENOMEM;
9fce074
+		  break;
9fce074
+		}
9fce074
 	    }
9fce074
 
9fce074
 	  if (rc6 != 0 && herrno == NETDB_INTERNAL)
ab21010
@@ -226,41 +236,38 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
9fce074
 	  while (1)
9fce074
 	    {
9fce074
 	      rc6 = 0;
9fce074
-	      status[0] = DL_CALL_FCT (fct, (key, AF_INET6, &th[0], tmpbuf6,
9fce074
-					     tmpbuf6len, &rc6, &herrno, &ttl,
9fce074
+	      status[0] = DL_CALL_FCT (fct, (key, AF_INET6, &th[0],
9fce074
+					     tmpbuf6.data, tmpbuf6.length,
9fce074
+					     &rc6, &herrno, &ttl,
9fce074
 					     &canon));
9fce074
 	      if (rc6 != ERANGE || herrno != NETDB_INTERNAL)
9fce074
 		break;
9fce074
-	      tmpbuf6 = extend_alloca (tmpbuf6, tmpbuf6len, 2 * tmpbuf6len);
9fce074
+	      if (!scratch_buffer_grow (&tmpbuf6))
9fce074
+		{
9fce074
+		  rc6 = ENOMEM;
9fce074
+		  break;
9fce074
+		}
9fce074
 	    }
9fce074
 
9fce074
 	  if (rc6 != 0 && herrno == NETDB_INTERNAL)
9fce074
 	    goto out;
9fce074
 
9fce074
-	  /* If the IPv6 lookup has been successful do not use the
9fce074
-	     buffer used in that lookup, use a new one.  */
9fce074
-	  if (status[0] == NSS_STATUS_SUCCESS && rc6 == 0)
9fce074
-	    {
9fce074
-	      tmpbuf4len = 512;
9fce074
-	      tmpbuf4 = alloca (tmpbuf4len);
9fce074
-	    }
9fce074
-	  else
9fce074
-	    {
9fce074
-	      tmpbuf4len = tmpbuf6len;
9fce074
-	      tmpbuf4 = tmpbuf6;
9fce074
-	    }
9fce074
-
9fce074
 	  /* Next collect IPv4 information.  */
9fce074
 	  while (1)
9fce074
 	    {
9fce074
 	      rc4 = 0;
9fce074
-	      status[1] = DL_CALL_FCT (fct, (key, AF_INET, &th[1], tmpbuf4,
9fce074
-					     tmpbuf4len, &rc4, &herrno,
9fce074
+	      status[1] = DL_CALL_FCT (fct, (key, AF_INET, &th[1],
9fce074
+					     tmpbuf4.data, tmpbuf4.length,
9fce074
+					     &rc4, &herrno,
9fce074
 					     ttl == INT32_MAX ? &ttl : NULL,
9fce074
 					     canon == NULL ? &canon : NULL));
9fce074
 	      if (rc4 != ERANGE || herrno != NETDB_INTERNAL)
9fce074
 		break;
9fce074
-	      tmpbuf4 = extend_alloca (tmpbuf4, tmpbuf4len, 2 * tmpbuf4len);
9fce074
+	      if (!scratch_buffer_grow (&tmpbuf4))
9fce074
+		{
9fce074
+		  rc4 = ENOMEM;
9fce074
+		  break;
9fce074
+		}
9fce074
 	    }
9fce074
 
9fce074
 	  if (rc4 != 0 && herrno == NETDB_INTERNAL)
ab21010
@@ -286,13 +293,11 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
9fce074
 	      cfct = __nss_lookup_function (nip, "getcanonname_r");
9fce074
 	      if (cfct != NULL)
9fce074
 		{
9fce074
-		  const size_t max_fqdn_len = 256;
9fce074
-		  char *buf = alloca (max_fqdn_len);
9fce074
 		  char *s;
9fce074
 		  int rc;
9fce074
 
9fce074
-		  if (DL_CALL_FCT (cfct, (key, buf, max_fqdn_len, &s,
9fce074
-					  &rc, &herrno))
9fce074
+		  if (DL_CALL_FCT (cfct, (key, canonbuf.data, canonbuf.length,
9fce074
+					  &s, &rc, &herrno))
9fce074
 		      == NSS_STATUS_SUCCESS)
9fce074
 		    canon = s;
9fce074
 		  else
ab21010
@@ -321,18 +326,20 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
9fce074
 		      addrfamily = AF_INET6;
9fce074
 		    }
9fce074
 
9fce074
-		  size_t tmpbuflen = 512;
9fce074
-		  char *tmpbuf = alloca (tmpbuflen);
9fce074
 		  int rc;
9fce074
 		  while (1)
9fce074
 		    {
9fce074
 		      rc = __gethostbyaddr2_r (addr, addrlen, addrfamily,
9fce074
-					       &hstent_mem, tmpbuf, tmpbuflen,
9fce074
+					       &hstent_mem,
9fce074
+					       canonbuf.data, canonbuf.length,
9fce074
 					       &hstent, &herrno, NULL);
9fce074
 		      if (rc != ERANGE || herrno != NETDB_INTERNAL)
9fce074
 			break;
9fce074
-		      tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
9fce074
-					      tmpbuflen * 2);
9fce074
+		      if (!scratch_buffer_grow (&canonbuf))
9fce074
+			{
9fce074
+			  rc = ENOMEM;
9fce074
+			  break;
9fce074
+			}
9fce074
 		    }
9fce074
 
9fce074
 		  if (rc == 0)
c659285
@@ -560,6 +567,10 @@ next_nip:
9fce074
 	dh->usable = false;
9fce074
     }
9fce074
 
9fce074
+  scratch_buffer_free (&tmpbuf6);
9fce074
+  scratch_buffer_free (&tmpbuf4);
9fce074
+  scratch_buffer_free (&canonbuf);
9fce074
+
9fce074
   return timeout;
9fce074
 }
9fce074
 
ab21010
diff --git a/nscd/connections.c b/nscd/connections.c
ab21010
index 26d2c0091b8f320d..9615c159285f0044 100644
9fce074
--- a/nscd/connections.c
9fce074
+++ b/nscd/connections.c
ab21010
@@ -1353,64 +1353,83 @@ request from '%s' [%ld] not handled due to missing permission"),
9fce074
     }
9fce074
 }
9fce074
 
9fce074
-
9fce074
-/* Restart the process.  */
9fce074
-static void
9fce074
-restart (void)
9fce074
+static char *
9fce074
+read_cmdline (size_t *size)
9fce074
 {
9fce074
-  /* First determine the parameters.  We do not use the parameters
9fce074
-     passed to main() since in case nscd is started by running the
9fce074
-     dynamic linker this will not work.  Yes, this is not the usual
9fce074
-     case but nscd is part of glibc and we occasionally do this.  */
9fce074
-  size_t buflen = 1024;
9fce074
-  char *buf = alloca (buflen);
9fce074
-  size_t readlen = 0;
9fce074
   int fd = open ("/proc/self/cmdline", O_RDONLY);
9fce074
-  if (fd == -1)
ddd7733
+  if (fd < 0)
ddd7733
+    return NULL;
ddd7733
+  size_t current = 0;
ddd7733
+  size_t limit = 1024;
ddd7733
+  char *buffer = malloc (limit);
ddd7733
+  if (buffer == NULL)
ab21010
     {
ab21010
-      dbg_log (_("\
ab21010
-cannot open /proc/self/cmdline: %s; disabling paranoia mode"),
ab21010
-	       strerror (errno));
ab21010
-
ab21010
-      paranoia = 0;
ab21010
-      return;
9fce074
+      close (fd);
9fce074
+      errno = ENOMEM;
9fce074
+      return NULL;
9fce074
     }
9fce074
-
9fce074
   while (1)
9fce074
     {
9fce074
-      ssize_t n = TEMP_FAILURE_RETRY (read (fd, buf + readlen,
9fce074
-					    buflen - readlen));
9fce074
-      if (n == -1)
9fce074
+      if (current == limit)
9fce074
 	{
9fce074
-	  dbg_log (_("\
9fce074
-cannot read /proc/self/cmdline: %s; disabling paranoia mode"),
9fce074
-		   strerror (errno));
9fce074
+	  char *newptr;
9fce074
+	  if (2 * limit < limit
9fce074
+	      || (newptr = realloc (buffer, 2 * limit)) == NULL)
9fce074
+	    {
9fce074
+	      free (buffer);
9fce074
+	      close (fd);
9fce074
+	      errno = ENOMEM;
9fce074
+	      return NULL;
9fce074
+	    }
9fce074
+	  buffer = newptr;
9fce074
+	  limit *= 2;
9fce074
+	}
9fce074
 
9fce074
+      ssize_t n = TEMP_FAILURE_RETRY (read (fd, buffer + current,
9fce074
+					    limit - current));
9fce074
+      if (n == -1)
9fce074
+	{
9fce074
+	  int e = errno;
9fce074
+	  free (buffer);
9fce074
 	  close (fd);
9fce074
-	  paranoia = 0;
9fce074
-	  return;
9fce074
+	  errno = e;
9fce074
+	  return NULL;
9fce074
 	}
9fce074
-
9fce074
-      readlen += n;
9fce074
-
9fce074
-      if (readlen < buflen)
9fce074
+      if (n == 0)
9fce074
 	break;
9fce074
-
9fce074
-      /* We might have to extend the buffer.  */
9fce074
-      size_t old_buflen = buflen;
9fce074
-      char *newp = extend_alloca (buf, buflen, 2 * buflen);
9fce074
-      buf = memmove (newp, buf, old_buflen);
9fce074
+      current += n;
9fce074
     }
9fce074
 
9fce074
   close (fd);
9fce074
+  *size = current;
9fce074
+  return buffer;
9fce074
+}
9fce074
+
9fce074
+
9fce074
+/* Restart the process.  */
9fce074
+static void
9fce074
+restart (void)
9fce074
+{
9fce074
+  /* First determine the parameters.  We do not use the parameters
9fce074
+     passed to main() because then nscd would would use the system
9fce074
+     libc after restarting even if it was started by a non-system
9fce074
+     dynamic linker during glibc testing.  */
9fce074
+  size_t readlen;
9fce074
+  char *cmdline = read_cmdline (&readlen);
9fce074
+  if (cmdline == NULL)
9fce074
+    {
9fce074
+      dbg_log (_("\
9fce074
+cannot open /proc/self/cmdline: %m; disabling paranoia mode"));
9fce074
+      paranoia = 0;
9fce074
+      return;
9fce074
+    }
9fce074
 
9fce074
   /* Parse the command line.  Worst case scenario: every two
9fce074
      characters form one parameter (one character plus NUL).  */
9fce074
   char **argv = alloca ((readlen / 2 + 1) * sizeof (argv[0]));
9fce074
   int argc = 0;
9fce074
 
9fce074
-  char *cp = buf;
9fce074
-  while (cp < buf + readlen)
9fce074
+  for (char *cp = cmdline; cp < cmdline + readlen;)
9fce074
     {
9fce074
       argv[argc++] = cp;
9fce074
       cp = (char *) rawmemchr (cp, '\0') + 1;
ab21010
@@ -1427,6 +1446,7 @@ cannot change to old UID: %s; disabling paranoia mode"),
9fce074
 		   strerror (errno));
9fce074
 
9fce074
 	  paranoia = 0;
9fce074
+	  free (cmdline);
9fce074
 	  return;
9fce074
 	}
9fce074
 
ab21010
@@ -1438,6 +1458,7 @@ cannot change to old GID: %s; disabling paranoia mode"),
9fce074
 
9fce074
 	  ignore_value (setuid (server_uid));
9fce074
 	  paranoia = 0;
9fce074
+	  free (cmdline);
9fce074
 	  return;
9fce074
 	}
9fce074
     }
ab21010
@@ -1455,6 +1476,7 @@ cannot change to old working directory: %s; disabling paranoia mode"),
9fce074
 	  ignore_value (setgid (server_gid));
9fce074
 	}
9fce074
       paranoia = 0;
9fce074
+      free (cmdline);
9fce074
       return;
9fce074
     }
9fce074
 
ab21010
@@ -1503,6 +1525,7 @@ cannot change to old working directory: %s; disabling paranoia mode"),
9fce074
     dbg_log (_("cannot change current working directory to \"/\": %s"),
9fce074
 	     strerror (errno));
9fce074
   paranoia = 0;
9fce074
+  free (cmdline);
9fce074
 
9fce074
   /* Reenable the databases.  */
9fce074
   time_t now = time (NULL);
ab21010
diff --git a/nscd/grpcache.c b/nscd/grpcache.c
ab21010
index d2ad53509db97bdf..a71036512048dd81 100644
9fce074
--- a/nscd/grpcache.c
9fce074
+++ b/nscd/grpcache.c
9fce074
@@ -16,7 +16,6 @@
9fce074
    You should have received a copy of the GNU General Public License
9fce074
    along with this program; if not, see <http://www.gnu.org/licenses/>.  */
9fce074
 
9fce074
-#include <alloca.h>
9fce074
 #include <assert.h>
9fce074
 #include <errno.h>
9fce074
 #include <error.h>
9fce074
@@ -32,6 +31,7 @@
9fce074
 #include <sys/mman.h>
9fce074
 #include <sys/socket.h>
9fce074
 #include <stackinfo.h>
9fce074
+#include <scratch_buffer.h>
9fce074
 
9fce074
 #include "nscd.h"
9fce074
 #include "dbg_log.h"
ab21010
@@ -448,12 +448,12 @@ addgrbyX (struct database_dyn *db, int fd, request_header *req,
9fce074
      look again in the table whether the dataset is now available.  We
9fce074
      simply insert it.  It does not matter if it is in there twice.  The
9fce074
      pruning function only will look at the timestamp.  */
9fce074
-  size_t buflen = 1024;
9fce074
-  char *buffer = (char *) alloca (buflen);
9fce074
+
9fce074
   struct group resultbuf;
9fce074
   struct group *grp;
9fce074
-  bool use_malloc = false;
9fce074
   int errval = 0;
9fce074
+  struct scratch_buffer tmpbuf;
9fce074
+  scratch_buffer_init (&tmpbuf);
9fce074
 
9fce074
   if (__glibc_unlikely (debug_level > 0))
9fce074
     {
ab21010
@@ -463,43 +463,24 @@ addgrbyX (struct database_dyn *db, int fd, request_header *req,
9fce074
 	dbg_log (_("Reloading \"%s\" in group cache!"), keystr);
9fce074
     }
9fce074
 
9fce074
-  while (lookup (req->type, key, &resultbuf, buffer, buflen, &grp) != 0
9fce074
+  while (lookup (req->type, key, &resultbuf,
9fce074
+		 tmpbuf.data, tmpbuf.length, &grp) != 0
9fce074
 	 && (errval = errno) == ERANGE)
9fce074
-    {
9fce074
-      errno = 0;
9fce074
-
9fce074
-      if (__glibc_unlikely (buflen > 32768))
9fce074
-	{
9fce074
-	  char *old_buffer = buffer;
9fce074
-	  buflen *= 2;
9fce074
-	  buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
9fce074
-	  if (buffer == NULL)
9fce074
-	    {
9fce074
-	      /* We ran out of memory.  We cannot do anything but
9fce074
-		 sending a negative response.  In reality this should
9fce074
-		 never happen.  */
9fce074
-	      grp = NULL;
9fce074
-	      buffer = old_buffer;
9fce074
-
9fce074
-	      /* We set the error to indicate this is (possibly) a
9fce074
-		 temporary error and that it does not mean the entry
9fce074
-		 is not available at all.  */
9fce074
-	      errval = EAGAIN;
9fce074
-	      break;
9fce074
-	    }
9fce074
-	  use_malloc = true;
9fce074
-	}
9fce074
-      else
9fce074
-	/* Allocate a new buffer on the stack.  If possible combine it
9fce074
-	   with the previously allocated buffer.  */
9fce074
-	buffer = (char *) extend_alloca (buffer, buflen, 2 * buflen);
9fce074
-    }
9fce074
+    if (!scratch_buffer_grow (&tmpbuf))
9fce074
+      {
9fce074
+	/* We ran out of memory.  We cannot do anything but sending a
9fce074
+	   negative response.  In reality this should never
9fce074
+	   happen.  */
9fce074
+	grp = NULL;
9fce074
+	/* We set the error to indicate this is (possibly) a temporary
9fce074
+	   error and that it does not mean the entry is not available
9fce074
+	   at all.  */
9fce074
+	errval = EAGAIN;
9fce074
+	break;
9fce074
+      }
9fce074
 
9fce074
   time_t timeout = cache_addgr (db, fd, req, keystr, grp, uid, he, dh, errval);
9fce074
-
9fce074
-  if (use_malloc)
9fce074
-    free (buffer);
9fce074
-
9fce074
+  scratch_buffer_free (&tmpbuf);
9fce074
   return timeout;
9fce074
 }
9fce074
 
ab21010
diff --git a/nscd/hstcache.c b/nscd/hstcache.c
ab21010
index 9f6ce979ac333265..d0af99893dd17b9f 100644
9fce074
--- a/nscd/hstcache.c
9fce074
+++ b/nscd/hstcache.c
9fce074
@@ -34,6 +34,7 @@
9fce074
 #include <arpa/nameser.h>
9fce074
 #include <sys/mman.h>
9fce074
 #include <stackinfo.h>
9fce074
+#include <scratch_buffer.h>
9fce074
 
9fce074
 #include "nscd.h"
9fce074
 #include "dbg_log.h"
ab21010
@@ -463,11 +464,8 @@ addhstbyX (struct database_dyn *db, int fd, request_header *req,
9fce074
      look again in the table whether the dataset is now available.  We
9fce074
      simply insert it.  It does not matter if it is in there twice.  The
9fce074
      pruning function only will look at the timestamp.  */
9fce074
-  int buflen = 1024;
9fce074
-  char *buffer = (char *) alloca (buflen);
9fce074
   struct hostent resultbuf;
9fce074
   struct hostent *hst;
9fce074
-  bool use_malloc = false;
9fce074
   int errval = 0;
9fce074
   int32_t ttl = INT32_MAX;
9fce074
 
ab21010
@@ -487,46 +485,30 @@ addhstbyX (struct database_dyn *db, int fd, request_header *req,
9fce074
 	dbg_log (_("Reloading \"%s\" in hosts cache!"), (char *) str);
9fce074
     }
9fce074
 
9fce074
-  while (lookup (req->type, key, &resultbuf, buffer, buflen, &hst, &ttl) != 0
9fce074
+  struct scratch_buffer tmpbuf;
9fce074
+  scratch_buffer_init (&tmpbuf);
9fce074
+
9fce074
+  while (lookup (req->type, key, &resultbuf,
9fce074
+		 tmpbuf.data, tmpbuf.length, &hst, &ttl) != 0
9fce074
 	 && h_errno == NETDB_INTERNAL
9fce074
 	 && (errval = errno) == ERANGE)
9fce074
-    {
9fce074
-      errno = 0;
9fce074
-
9fce074
-      if (__glibc_unlikely (buflen > 32768))
9fce074
-	{
9fce074
-	  char *old_buffer = buffer;
9fce074
-	  buflen *= 2;
9fce074
-	  buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
9fce074
-	  if (buffer == NULL)
9fce074
-	    {
9fce074
-	      /* We ran out of memory.  We cannot do anything but
9fce074
-		 sending a negative response.  In reality this should
9fce074
-		 never happen.  */
9fce074
-	      hst = NULL;
9fce074
-	      buffer = old_buffer;
9fce074
-
9fce074
-	      /* We set the error to indicate this is (possibly) a
9fce074
-		 temporary error and that it does not mean the entry
9fce074
-		 is not available at all.  */
9fce074
-	      h_errno = TRY_AGAIN;
9fce074
-	      errval = EAGAIN;
9fce074
-	      break;
9fce074
-	    }
9fce074
-	  use_malloc = true;
9fce074
-	}
9fce074
-      else
9fce074
-	/* Allocate a new buffer on the stack.  If possible combine it
9fce074
-	   with the previously allocated buffer.  */
9fce074
-	buffer = (char *) extend_alloca (buffer, buflen, 2 * buflen);
9fce074
-    }
9fce074
+    if (!scratch_buffer_grow (&tmpbuf))
9fce074
+      {
9fce074
+	/* We ran out of memory.  We cannot do anything but sending a
9fce074
+	   negative response.  In reality this should never
9fce074
+	   happen.  */
9fce074
+	hst = NULL;
9fce074
+	/* We set the error to indicate this is (possibly) a temporary
9fce074
+	   error and that it does not mean the entry is not
9fce074
+	   available at all.  */
9fce074
+	h_errno = TRY_AGAIN;
9fce074
+	errval = EAGAIN;
9fce074
+	break;
9fce074
+      }
9fce074
 
9fce074
   time_t timeout = cache_addhst (db, fd, req, key, hst, uid, he, dh,
9fce074
 				 h_errno == TRY_AGAIN ? errval : 0, ttl);
9fce074
-
9fce074
-  if (use_malloc)
9fce074
-    free (buffer);
9fce074
-
9fce074
+  scratch_buffer_free (&tmpbuf);
9fce074
   return timeout;
9fce074
 }
9fce074
 
ab21010
diff --git a/nscd/pwdcache.c b/nscd/pwdcache.c
ab21010
index 721f4c617b0bb74a..9349b54df4241ad5 100644
9fce074
--- a/nscd/pwdcache.c
9fce074
+++ b/nscd/pwdcache.c
9fce074
@@ -16,7 +16,6 @@
9fce074
    You should have received a copy of the GNU General Public License
9fce074
    along with this program; if not, see <http://www.gnu.org/licenses/>.  */
9fce074
 
9fce074
-#include <alloca.h>
9fce074
 #include <assert.h>
9fce074
 #include <errno.h>
9fce074
 #include <error.h>
9fce074
@@ -32,6 +31,7 @@
9fce074
 #include <sys/mman.h>
9fce074
 #include <sys/socket.h>
9fce074
 #include <stackinfo.h>
9fce074
+#include <scratch_buffer.h>
9fce074
 
9fce074
 #include "nscd.h"
9fce074
 #include "dbg_log.h"
ab21010
@@ -426,12 +426,11 @@ addpwbyX (struct database_dyn *db, int fd, request_header *req,
9fce074
      look again in the table whether the dataset is now available.  We
9fce074
      simply insert it.  It does not matter if it is in there twice.  The
9fce074
      pruning function only will look at the timestamp.  */
9fce074
-  size_t buflen = 1024;
9fce074
-  char *buffer = (char *) alloca (buflen);
9fce074
   struct passwd resultbuf;
9fce074
   struct passwd *pwd;
9fce074
-  bool use_malloc = false;
9fce074
   int errval = 0;
9fce074
+  struct scratch_buffer tmpbuf;
9fce074
+  scratch_buffer_init (&tmpbuf);
9fce074
 
9fce074
   if (__glibc_unlikely (debug_level > 0))
9fce074
     {
ab21010
@@ -441,45 +440,26 @@ addpwbyX (struct database_dyn *db, int fd, request_header *req,
9fce074
 	dbg_log (_("Reloading \"%s\" in password cache!"), keystr);
9fce074
     }
9fce074
 
9fce074
-  while (lookup (req->type, key, &resultbuf, buffer, buflen, &pwd) != 0
9fce074
+  while (lookup (req->type, key, &resultbuf,
9fce074
+		 tmpbuf.data, tmpbuf.length, &pwd) != 0
9fce074
 	 && (errval = errno) == ERANGE)
9fce074
-    {
9fce074
-      errno = 0;
9fce074
-
9fce074
-      if (__glibc_unlikely (buflen > 32768))
9fce074
-	{
9fce074
-	  char *old_buffer = buffer;
9fce074
-	  buflen *= 2;
9fce074
-	  buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
9fce074
-	  if (buffer == NULL)
9fce074
-	    {
9fce074
-	      /* We ran out of memory.  We cannot do anything but
9fce074
-		 sending a negative response.  In reality this should
9fce074
-		 never happen.  */
9fce074
-	      pwd = NULL;
9fce074
-	      buffer = old_buffer;
9fce074
-
9fce074
-	      /* We set the error to indicate this is (possibly) a
9fce074
-		 temporary error and that it does not mean the entry
9fce074
-		 is not available at all.  */
9fce074
-	      errval = EAGAIN;
9fce074
-	      break;
9fce074
-	    }
9fce074
-	  use_malloc = true;
9fce074
-	}
9fce074
-      else
9fce074
-	/* Allocate a new buffer on the stack.  If possible combine it
9fce074
-	   with the previously allocated buffer.  */
9fce074
-	buffer = (char *) extend_alloca (buffer, buflen, 2 * buflen);
9fce074
-    }
9fce074
+    if (!scratch_buffer_grow (&tmpbuf))
9fce074
+      {
9fce074
+	/* We ran out of memory.  We cannot do anything but sending a
9fce074
+	   negative response.  In reality this should never
9fce074
+	   happen.  */
9fce074
+	pwd = NULL;
9fce074
+	/* We set the error to indicate this is (possibly) a temporary
9fce074
+	   error and that it does not mean the entry is not available
9fce074
+	   at all.  */
9fce074
+	errval = EAGAIN;
9fce074
+	break;
9fce074
+      }
9fce074
 
9fce074
   /* Add the entry to the cache.  */
9fce074
   time_t timeout = cache_addpw (db, fd, req, keystr, pwd, c_uid, he, dh,
9fce074
 				errval);
9fce074
-
9fce074
-  if (use_malloc)
9fce074
-    free (buffer);
9fce074
-
9fce074
+  scratch_buffer_free (&tmpbuf);
9fce074
   return timeout;
9fce074
 }
9fce074
 
ab21010
diff --git a/nscd/servicescache.c b/nscd/servicescache.c
ab21010
index 131ba6ddcc1a5f7a..549e9a446816d760 100644
9fce074
--- a/nscd/servicescache.c
9fce074
+++ b/nscd/servicescache.c
9fce074
@@ -16,7 +16,6 @@
9fce074
    You should have received a copy of the GNU General Public License
9fce074
    along with this program; if not, see <http://www.gnu.org/licenses/>.  */
9fce074
 
9fce074
-#include <alloca.h>
9fce074
 #include <assert.h>
9fce074
 #include <errno.h>
9fce074
 #include <libintl.h>
9fce074
@@ -25,6 +24,7 @@
9fce074
 #include <stdint.h>
9fce074
 #include <sys/mman.h>
9fce074
 #include <kernel-features.h>
9fce074
+#include <scratch_buffer.h>
9fce074
 
9fce074
 #include "nscd.h"
9fce074
 #include "dbg_log.h"
ab21010
@@ -374,12 +374,11 @@ addservbyX (struct database_dyn *db, int fd, request_header *req,
9fce074
      look again in the table whether the dataset is now available.  We
9fce074
      simply insert it.  It does not matter if it is in there twice.  The
9fce074
      pruning function only will look at the timestamp.  */
9fce074
-  size_t buflen = 1024;
9fce074
-  char *buffer = (char *) alloca (buflen);
9fce074
   struct servent resultbuf;
9fce074
   struct servent *serv;
9fce074
-  bool use_malloc = false;
9fce074
   int errval = 0;
9fce074
+  struct scratch_buffer tmpbuf;
9fce074
+  scratch_buffer_init (&tmpbuf);
9fce074
 
9fce074
   if (__glibc_unlikely (debug_level > 0))
9fce074
     {
ab21010
@@ -389,43 +388,24 @@ addservbyX (struct database_dyn *db, int fd, request_header *req,
9fce074
 	dbg_log (_("Reloading \"%s\" in services cache!"), key);
9fce074
     }
9fce074
 
9fce074
-  while (lookup (req->type, key, &resultbuf, buffer, buflen, &serv) != 0
9fce074
+  while (lookup (req->type, key, &resultbuf,
9fce074
+		 tmpbuf.data, tmpbuf.length, &serv) != 0
9fce074
 	 && (errval = errno) == ERANGE)
9fce074
-    {
9fce074
-      errno = 0;
9fce074
-
9fce074
-      if (__glibc_unlikely (buflen > 32768))
9fce074
-	{
9fce074
-	  char *old_buffer = buffer;
9fce074
-	  buflen *= 2;
9fce074
-	  buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
9fce074
-	  if (buffer == NULL)
9fce074
-	    {
9fce074
-	      /* We ran out of memory.  We cannot do anything but
9fce074
-		 sending a negative response.  In reality this should
9fce074
-		 never happen.  */
9fce074
-	      serv = NULL;
9fce074
-	      buffer = old_buffer;
9fce074
-
9fce074
-	      /* We set the error to indicate this is (possibly) a
9fce074
-		 temporary error and that it does not mean the entry
9fce074
-		 is not available at all.  */
9fce074
-	      errval = EAGAIN;
9fce074
-	      break;
9fce074
-	    }
9fce074
-	  use_malloc = true;
9fce074
-	}
9fce074
-      else
9fce074
-	/* Allocate a new buffer on the stack.  If possible combine it
9fce074
-	   with the previously allocated buffer.  */
9fce074
-	buffer = (char *) extend_alloca (buffer, buflen, 2 * buflen);
9fce074
-    }
9fce074
+    if (!scratch_buffer_grow (&tmpbuf))
9fce074
+      {
9fce074
+	/* We ran out of memory.  We cannot do anything but sending a
9fce074
+	   negative response.  In reality this should never
9fce074
+	   happen.  */
9fce074
+	serv = NULL;
9fce074
+	/* We set the error to indicate this is (possibly) a temporary
9fce074
+	   error and that it does not mean the entry is not available
9fce074
+	   at all.  */
9fce074
+	errval = EAGAIN;
9fce074
+	break;
9fce074
+      }
9fce074
 
9fce074
   time_t timeout = cache_addserv (db, fd, req, key, serv, uid, he, dh, errval);
9fce074
-
9fce074
-  if (use_malloc)
9fce074
-    free (buffer);
9fce074
-
9fce074
+  scratch_buffer_free (&tmpbuf);
9fce074
   return timeout;
9fce074
 }
9fce074
 
ab21010
diff --git a/nss/getent.c b/nss/getent.c
ab21010
index 8f8c3fe80a2cfea6..5654c5f67c4f118c 100644
9fce074
--- a/nss/getent.c
9fce074
+++ b/nss/getent.c
9fce074
@@ -39,6 +39,7 @@
9fce074
 #include <netinet/ether.h>
9fce074
 #include <netinet/in.h>
9fce074
 #include <sys/socket.h>
9fce074
+#include <scratch_buffer.h>
9fce074
 
9fce074
 /* Get libc version number.  */
9fce074
 #include <version.h>
9fce074
@@ -477,30 +478,34 @@ netgroup_keys (int number, char *key[])
9fce074
 static int
9fce074
 initgroups_keys (int number, char *key[])
9fce074
 {
9fce074
-  int ngrps = 100;
9fce074
-  size_t grpslen = ngrps * sizeof (gid_t);
9fce074
-  gid_t *grps = alloca (grpslen);
9fce074
-
9fce074
   if (number == 0)
9fce074
     {
9fce074
       fprintf (stderr, _("Enumeration not supported on %s\n"), "initgroups");
9fce074
       return 3;
9fce074
     }
9fce074
 
9fce074
+  struct scratch_buffer tmpbuf;
9fce074
+  scratch_buffer_init (&tmpbuf);
9fce074
+
9fce074
   for (int i = 0; i < number; ++i)
9fce074
     {
9fce074
+      ssize_t ngrps = tmpbuf.length / sizeof (gid_t);
9fce074
       int no = ngrps;
9fce074
       int n;
9fce074
-      while ((n = getgrouplist (key[i], -1, grps, &no)) == -1
9fce074
+      while ((n = getgrouplist (key[i], -1, tmpbuf.data, &no)) == -1
9fce074
 	     && no > ngrps)
9fce074
 	{
9fce074
-	  grps = extend_alloca (grps, grpslen, no * sizeof (gid_t));
9fce074
-	  ngrps = no;
9fce074
+	  if (!scratch_buffer_set_array_size (&tmpbuf, no, sizeof (gid_t)))
9fce074
+	    {
9fce074
+	      fprintf (stderr, _("Could not allocate group list: %m\n"));
9fce074
+	      return 3;
9fce074
+	    }
9fce074
 	}
9fce074
 
9fce074
       if (n == -1)
9fce074
 	return 1;
9fce074
 
9fce074
+      const gid_t *grps = tmpbuf.data;
9fce074
       printf ("%-21s", key[i]);
9fce074
       for (int j = 0; j < n; ++j)
9fce074
 	if (grps[j] != -1)
ab21010
@@ -508,6 +513,8 @@ initgroups_keys (int number, char *key[])
9fce074
       putchar_unlocked ('\n');
9fce074
     }
9fce074
 
9fce074
+  scratch_buffer_free (&tmpbuf);
9fce074
+
9fce074
   return 0;
9fce074
 }
9fce074
 
ab21010
diff --git a/nss/nss_files/files-initgroups.c b/nss/nss_files/files-initgroups.c
ab21010
index 27cd8ece40434f5c..8a88f1b62357d3bd 100644
9fce074
--- a/nss/nss_files/files-initgroups.c
9fce074
+++ b/nss/nss_files/files-initgroups.c
9fce074
@@ -16,7 +16,6 @@
9fce074
    License along with the GNU C Library; if not, see
9fce074
    <http://www.gnu.org/licenses/>.  */
9fce074
 
9fce074
-#include <alloca.h>
9fce074
 #include <errno.h>
9fce074
 #include <grp.h>
9fce074
 #include <nss.h>
9fce074
@@ -25,6 +24,7 @@
9fce074
 #include <sys/param.h>
9fce074
 #include <stdbool.h>
9fce074
 #include <stdlib.h>
9fce074
+#include <scratch_buffer.h>
9fce074
 
9fce074
 enum nss_status
9fce074
 _nss_files_initgroups_dyn (const char *user, gid_t group, long int *start,
ab21010
@@ -46,9 +46,8 @@ _nss_files_initgroups_dyn (const char *user, gid_t group, long int *start,
9fce074
   enum nss_status status = NSS_STATUS_SUCCESS;
9fce074
   bool any = false;
9fce074
 
9fce074
-  size_t buflen = 1024;
9fce074
-  void *buffer = alloca (buflen);
9fce074
-  bool buffer_use_malloc = false;
9fce074
+  struct scratch_buffer tmpbuf;
9fce074
+  scratch_buffer_init (&tmpbuf);
9fce074
 
9fce074
   gid_t *groups = *groupsp;
9fce074
 
ab21010
@@ -67,26 +66,16 @@ _nss_files_initgroups_dyn (const char *user, gid_t group, long int *start,
9fce074
 	}
9fce074
 
9fce074
       struct group grp;
9fce074
-      int res = _nss_files_parse_grent (line, &grp, buffer, buflen, errnop);
9fce074
+      int res = _nss_files_parse_grent (line, &grp,
9fce074
+					tmpbuf.data, tmpbuf.length, errnop);
9fce074
       if (res == -1)
9fce074
 	{
9fce074
-	  size_t newbuflen = 2 * buflen;
9fce074
-	  if (buffer_use_malloc || ! __libc_use_alloca (buflen + newbuflen))
9fce074
+	  if (!scratch_buffer_grow (&tmpbuf))
9fce074
 	    {
9fce074
-	      void *newbuf = realloc (buffer_use_malloc ? buffer : NULL,
9fce074
-				      newbuflen);
9fce074
-	      if (newbuf == NULL)
9fce074
-		{
9fce074
-		  *errnop = ENOMEM;
9fce074
-		  status = NSS_STATUS_TRYAGAIN;
9fce074
-		  goto out;
9fce074
-		}
9fce074
-	      buffer = newbuf;
9fce074
-	      buflen = newbuflen;
9fce074
-	      buffer_use_malloc = true;
9fce074
+	      *errnop = ENOMEM;
9fce074
+	      status = NSS_STATUS_TRYAGAIN;
9fce074
+	      goto out;
9fce074
 	    }
9fce074
-	  else
9fce074
-	    buffer = extend_alloca (buffer, buflen, newbuflen);
9fce074
 	  /* Reread current line, the parser has clobbered it.  */
9fce074
 	  fsetpos (stream, &pos;;
9fce074
 	  continue;
ab21010
@@ -132,8 +121,7 @@ _nss_files_initgroups_dyn (const char *user, gid_t group, long int *start,
9fce074
 
9fce074
  out:
9fce074
   /* Free memory.  */
9fce074
-  if (buffer_use_malloc)
9fce074
-    free (buffer);
9fce074
+  scratch_buffer_free (&tmpbuf);
9fce074
   free (line);
9fce074
 
9fce074
   fclose (stream);
ab21010
diff --git a/posix/wordexp.c b/posix/wordexp.c
ab21010
index ba3f3ed4b66a6507..c4a6a209f416a9fb 100644
9fce074
--- a/posix/wordexp.c
9fce074
+++ b/posix/wordexp.c
9fce074
@@ -17,7 +17,6 @@
9fce074
    License along with the GNU C Library; if not, see
9fce074
    <http://www.gnu.org/licenses/>.  */
9fce074
 
9fce074
-#include <alloca.h>
9fce074
 #include <ctype.h>
9fce074
 #include <errno.h>
9fce074
 #include <fcntl.h>
9fce074
@@ -41,6 +40,7 @@
9fce074
 #include <wchar.h>
9fce074
 #include <wordexp.h>
9fce074
 #include <kernel-features.h>
9fce074
+#include <scratch_buffer.h>
9fce074
 
9fce074
 #include <libc-lock.h>
9fce074
 #include <_itoa.h>
ab21010
@@ -308,12 +308,7 @@ parse_tilde (char **word, size_t *word_length, size_t *max_length,
9fce074
   if (i == 1 + *offset)
9fce074
     {
9fce074
       /* Tilde appears on its own */
9fce074
-      uid_t uid;
9fce074
-      struct passwd pwd, *tpwd;
9fce074
-      int buflen = 1000;
9fce074
       char* home;
9fce074
-      char* buffer;
9fce074
-      int result;
9fce074
 
9fce074
       /* POSIX.2 says ~ expands to $HOME and if HOME is unset the
9fce074
 	 results are unspecified.  We do a lookup on the uid if
ab21010
@@ -328,25 +323,38 @@ parse_tilde (char **word, size_t *word_length, size_t *max_length,
9fce074
 	}
9fce074
       else
9fce074
 	{
9fce074
-	  uid = __getuid ();
9fce074
-	  buffer = __alloca (buflen);
9fce074
-
9fce074
-	  while ((result = __getpwuid_r (uid, &pwd, buffer, buflen, &tpwd)) != 0
9fce074
+	  struct passwd pwd, *tpwd;
9fce074
+	  uid_t uid = __getuid ();
9fce074
+	  int result;
9fce074
+	  struct scratch_buffer tmpbuf;
9fce074
+	  scratch_buffer_init (&tmpbuf);
9fce074
+
9fce074
+	  while ((result = __getpwuid_r (uid, &pwd,
9fce074
+					 tmpbuf.data, tmpbuf.length,
9fce074
+					 &tpwd)) != 0
9fce074
 		 && errno == ERANGE)
9fce074
-	    buffer = extend_alloca (buffer, buflen, buflen + 1000);
9fce074
+	    if (!scratch_buffer_grow (&tmpbuf))
9fce074
+	      return WRDE_NOSPACE;
9fce074
 
9fce074
 	  if (result == 0 && tpwd != NULL && pwd.pw_dir != NULL)
9fce074
 	    {
9fce074
 	      *word = w_addstr (*word, word_length, max_length, pwd.pw_dir);
9fce074
 	      if (*word == NULL)
9fce074
-		return WRDE_NOSPACE;
9fce074
+		{
9fce074
+		  scratch_buffer_free (&tmpbuf);
9fce074
+		  return WRDE_NOSPACE;
9fce074
+		}
9fce074
 	    }
9fce074
 	  else
9fce074
 	    {
9fce074
 	      *word = w_addchar (*word, word_length, max_length, '~');
9fce074
 	      if (*word == NULL)
9fce074
-		return WRDE_NOSPACE;
9fce074
+		{
9fce074
+		  scratch_buffer_free (&tmpbuf);
9fce074
+		  return WRDE_NOSPACE;
9fce074
+		}
9fce074
 	    }
9fce074
+	  scratch_buffer_free (&tmpbuf);
9fce074
 	}
9fce074
     }
9fce074
   else
ab21010
@@ -354,13 +362,15 @@ parse_tilde (char **word, size_t *word_length, size_t *max_length,
9fce074
       /* Look up user name in database to get home directory */
9fce074
       char *user = strndupa (&words[1 + *offset], i - (1 + *offset));
9fce074
       struct passwd pwd, *tpwd;
9fce074
-      int buflen = 1000;
9fce074
-      char* buffer = __alloca (buflen);
9fce074
       int result;
9fce074
+      struct scratch_buffer tmpbuf;
9fce074
+      scratch_buffer_init (&tmpbuf);
9fce074
 
9fce074
-      while ((result = __getpwnam_r (user, &pwd, buffer, buflen, &tpwd)) != 0
9fce074
+      while ((result = __getpwnam_r (user, &pwd, tmpbuf.data, tmpbuf.length,
9fce074
+				     &tpwd)) != 0
9fce074
 	     && errno == ERANGE)
9fce074
-	buffer = extend_alloca (buffer, buflen, buflen + 1000);
9fce074
+	if (!scratch_buffer_grow (&tmpbuf))
9fce074
+	  return WRDE_NOSPACE;
9fce074
 
9fce074
       if (result == 0 && tpwd != NULL && pwd.pw_dir)
9fce074
 	*word = w_addstr (*word, word_length, max_length, pwd.pw_dir);
ab21010
@@ -372,6 +382,8 @@ parse_tilde (char **word, size_t *word_length, size_t *max_length,
9fce074
 	    *word = w_addstr (*word, word_length, max_length, user);
9fce074
 	}
9fce074
 
9fce074
+      scratch_buffer_free (&tmpbuf);
9fce074
+
9fce074
       *offset = i - 1;
9fce074
     }
9fce074
   return *word ? 0 : WRDE_NOSPACE;
ab21010
diff --git a/sysdeps/unix/sysv/linux/gethostid.c b/sysdeps/unix/sysv/linux/gethostid.c
ab21010
index cc108aa2d64b616a..3529cf6fe509cfd1 100644
9fce074
--- a/sysdeps/unix/sysv/linux/gethostid.c
9fce074
+++ b/sysdeps/unix/sysv/linux/gethostid.c
9fce074
@@ -63,13 +63,12 @@ sethostid (long int id)
9fce074
 # include <sys/param.h>
9fce074
 # include <resolv/netdb.h>
9fce074
 # include <netinet/in.h>
9fce074
+# include <scratch_buffer.h>
9fce074
 
9fce074
 long int
9fce074
 gethostid (void)
9fce074
 {
9fce074
   char hostname[MAXHOSTNAMELEN + 1];
9fce074
-  size_t buflen;
9fce074
-  char *buffer;
9fce074
   struct hostent hostbuf, *hp;
9fce074
   int32_t id;
9fce074
   struct in_addr in;
9fce074
@@ -94,23 +93,26 @@ gethostid (void)
9fce074
     /* This also fails.  Return and arbitrary value.  */
9fce074
     return 0;
9fce074
 
9fce074
-  buflen = 1024;
9fce074
-  buffer = __alloca (buflen);
9fce074
+  struct scratch_buffer tmpbuf;
9fce074
+  scratch_buffer_init (&tmpbuf);
9fce074
 
9fce074
   /* To get the IP address we need to know the host name.  */
9fce074
-  while (__gethostbyname_r (hostname, &hostbuf, buffer, buflen, &hp, &herr)
9fce074
-	 != 0
9fce074
+  while (__gethostbyname_r (hostname, &hostbuf,
9fce074
+			    tmpbuf.data, tmpbuf.length, &hp, &herr) != 0
9fce074
 	 || hp == NULL)
9fce074
     if (herr != NETDB_INTERNAL || errno != ERANGE)
9fce074
-      return 0;
9fce074
+      {
9fce074
+	scratch_buffer_free (&tmpbuf);
9fce074
+	return 0;
9fce074
+      }
9fce074
     else
9fce074
-      /* Enlarge buffer.  */
9fce074
-      buffer = extend_alloca (buffer, buflen, 2 * buflen);
9fce074
+      if (!scratch_buffer_grow (&tmpbuf))
9fce074
+	return 0;
9fce074
 
9fce074
   in.s_addr = 0;
9fce074
   memcpy (&in, hp->h_addr,
9fce074
 	  (int) sizeof (in) < hp->h_length ? (int) sizeof (in) : hp->h_length);
9fce074
-
9fce074
+  scratch_buffer_free (&tmpbuf);
9fce074
   /* For the return value to be not exactly the IP address we do some
9fce074
      bit fiddling.  */
9fce074
   return (int32_t) (in.s_addr << 16 | in.s_addr >> 16);
ab21010
diff --git a/sysdeps/unix/sysv/linux/getlogin_r.c b/sysdeps/unix/sysv/linux/getlogin_r.c
ab21010
index 05ac36b49186b29e..37a9255e03657728 100644
9fce074
--- a/sysdeps/unix/sysv/linux/getlogin_r.c
9fce074
+++ b/sysdeps/unix/sysv/linux/getlogin_r.c
9fce074
@@ -18,6 +18,7 @@
9fce074
 #include <pwd.h>
9fce074
 #include <unistd.h>
9fce074
 #include <not-cancel.h>
9fce074
+#include <scratch_buffer.h>
9fce074
 
9fce074
 #define STATIC static
9fce074
 static int getlogin_r_fd0 (char *name, size_t namesize);
ab21010
@@ -54,28 +55,19 @@ __getlogin_r_loginuid (char *name, size_t namesize)
9fce074
 	  endp == uidbuf || *endp != '\0'))
9fce074
     return -1;
9fce074
 
9fce074
-  size_t buflen = 1024;
9fce074
-  char *buf = alloca (buflen);
9fce074
-  bool use_malloc = false;
9fce074
   struct passwd pwd;
9fce074
   struct passwd *tpwd;
9fce074
   int result = 0;
9fce074
   int res;
9fce074
+  struct scratch_buffer tmpbuf;
9fce074
+  scratch_buffer_init (&tmpbuf);
9fce074
 
9fce074
-  while ((res = __getpwuid_r (uid, &pwd, buf, buflen, &tpwd)) == ERANGE)
9fce074
-    if (__libc_use_alloca (2 * buflen))
9fce074
-      buf = extend_alloca (buf, buflen, 2 * buflen);
9fce074
-    else
9fce074
+  while ((res = __getpwuid_r (uid, &pwd,
9fce074
+			      tmpbuf.data, tmpbuf.length, &tpwd)) == ERANGE)
9fce074
+    if (!scratch_buffer_grow (&tmpbuf))
9fce074
       {
9fce074
-	buflen *= 2;
9fce074
-	char *newp = realloc (use_malloc ? buf : NULL, buflen);
9fce074
-	if (newp == NULL)
9fce074
-	  {
9fce074
-	    result = ENOMEM;
9fce074
-	    goto out;
9fce074
-	  }
9fce074
-	buf = newp;
9fce074
-	use_malloc = true;
9fce074
+	result = ENOMEM;
9fce074
+	goto out;
9fce074
       }
9fce074
 
9fce074
   if (res != 0 || tpwd == NULL)
ab21010
@@ -95,9 +87,7 @@ __getlogin_r_loginuid (char *name, size_t namesize)
9fce074
   memcpy (name, pwd.pw_name, needed);
9fce074
 
9fce074
  out:
9fce074
-  if (use_malloc)
9fce074
-    free (buf);
9fce074
-
9fce074
+  scratch_buffer_free (&tmpbuf);
9fce074
   return result;
9fce074
 }
9fce074