From 9fce0748c4d989e603d379d80f2066d8061de932 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Mon, 7 Mar 2016 06:52:27 +0100 Subject: [PATCH] Resolves: #1315108 Remove extend_alloca. --- glibc-rh1315108.patch | 2190 +++++++++++++++++++++++++++++++++++++++++ glibc.spec | 9 +- series | 1 + 3 files changed, 2199 insertions(+), 1 deletion(-) create mode 100644 glibc-rh1315108.patch diff --git a/glibc-rh1315108.patch b/glibc-rh1315108.patch new file mode 100644 index 0000000..efac5c9 --- /dev/null +++ b/glibc-rh1315108.patch @@ -0,0 +1,2190 @@ +From the upstream branch fw/extend_alloca. + +commit dc79f9aa56933dc8b475209f9a4059965b50ea26 +Author: Florian Weimer +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. + +commit 9bed8b7fca7867d3027b66ce3985a75136aed013 +Author: Florian Weimer +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. + +commit c95cc759ecb21f812872934ac55518aef28cf46b +Author: Florian Weimer +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. + +commit e38bff4db6f03d1fab732737f43a25160c3e4703 +Author: Florian Weimer +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. + +commit 8825d4709a686a870d313cc602d489ddd5354a08 +Author: Florian Weimer +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. + +commit 140d8711d446f5193b04b56e714ddf8d0eddbf62 +Author: Florian Weimer +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. + +commit 1af14faef808f03276766e5ee6d9ee7dc9053fba +Author: Florian Weimer +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. + +commit 9b71d3b4df6dd4e49f7638d1d936c921c50fa3d9 +Author: Florian Weimer +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. + +commit 11c2a8bad9ca5fe510b73c0204b3dcf703f14d5c +Author: Florian Weimer +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. + +commit 6de00dd8a3a76d0b7586393451e65ad6c2721a71 +Author: Florian Weimer +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. + +commit f414b3f5947f264cb5d114965f284cacb2fb10b5 +Author: Florian Weimer +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. + +commit 488063238ee5c87b66c6982b1b6d508e30e44386 +Author: Florian Weimer +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. + +commit 7b4c16db30304b83a5d1e913d1a8f7e90a8c398c +Author: Florian Weimer +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. + +commit 683543bbb3e2c1b17554c4096d00c2980f39a802 +Author: Florian Weimer +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/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 + #include + #include ++#include + + #include + +@@ -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); + +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 + +-#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 +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); + } + +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 + . */ + +-#include + #include + #include + #include +@@ -27,6 +26,7 @@ + #include + #include + #include ++#include + + #include "nss-nis.h" + #include +@@ -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; + } +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 + #include + #include ++#include + + #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; + } + +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); +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 . */ + +-#include + #include + #include + #include +@@ -32,6 +31,7 @@ + #include + #include + #include ++#include + + #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 + #include + #include ++#include + + #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 . */ + +-#include + #include + #include + #include +@@ -32,6 +31,7 @@ + #include + #include + #include ++#include + + #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 . */ + +-#include + #include + #include + #include +@@ -25,6 +24,7 @@ + #include + #include + #include ++#include + + #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; + } + +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 + #include + #include ++#include + + /* Get libc version number. */ + #include +@@ -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; + } + +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 + #include + #include +- ++#include + + /* 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 + . */ + +-#include + #include + #include + #include +@@ -25,6 +24,7 @@ + #include + #include + #include ++#include + + 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); +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 + #include + #include ++#include + + /* 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 +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 + . */ + +-#include + #include + #include + #include +@@ -41,6 +40,7 @@ + #include + #include + #include ++#include + + #include + #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; +diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c +index 1ef3f20..1d712af 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 + #include + #include ++#include + + #ifdef HAVE_LIBIDN + extern int __idna_to_ascii_lz (const char *input, char **output, int flags); +@@ -138,21 +139,22 @@ 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; + } +@@ -164,7 +166,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 +180,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 +272,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 +396,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 +567,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 +576,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 +806,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 +826,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 +842,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 +1233,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; + } +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 + # include + # include ++# include + + 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); +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 + #include + #include ++#include + + #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; + } + diff --git a/glibc.spec b/glibc.spec index 6d1e707..072974d 100644 --- a/glibc.spec +++ b/glibc.spec @@ -1,6 +1,6 @@ %define glibcsrcdir glibc-2.23-40-gde51ff8 %define glibcversion 2.23.90 -%define glibcrelease 3%{?dist} +%define glibcrelease 4%{?dist} # Pre-release tarballs are pulled in from git using a command that is # effectively: # @@ -295,6 +295,9 @@ Patch2035: glibc-nsswitch-Add-group-merging-support.patch Patch2036: glibc-gcc-PR69537.patch +# extend_alloca removal, BZ 18023 +Patch2037: glibc-rh1315108.patch + # Upstream BZ 19573, patch reverts problematic commit Patch2099: glibc-rh1252570.patch @@ -788,6 +791,7 @@ cat /proc/meminfo %patch0059 -p1 %patch2035 -p1 %patch2036 -p1 +%patch2037 -p1 %patch2099 -p1 ############################################################################## @@ -2088,6 +2092,9 @@ rm -f *.filelist* %endif %changelog +* Sun Mar 6 2016 Florian Weimer - 2.23.90-4 +- Remove extend_alloca (#1315108) + * Mon Feb 29 2016 Carlos O'Donell - 2.23.90-3 - Enhance support for upgrading from a non-language-pack system. diff --git a/series b/series index 9b34d6b..1810c7f 100644 --- a/series +++ b/series @@ -39,3 +39,4 @@ glibc-c-utf8-locale.patch -p1 --fuzz=0 glibc-nsswitch-Add-group-merging-support.patch -p1 --fuzz=0 glibc-gcc-PR69537.patch -p1 --fuzz=0 glibc-rh1252570.patch -p1 --fuzz=0 +glibc-rh1315108.patch -p1