glibc/glibc-rh1315108.patch

1947 lines
56 KiB
Diff
Raw Normal View History

From the upstream branch fw/extend_alloca.
commit dc79f9aa56933dc8b475209f9a4059965b50ea26
Author: Florian Weimer <fweimer@redhat.com>
Date: Sun Mar 1 18:29:47 2015 +0100
nscd restart: Use malloc instead of extend_alloca
This introduces a separate function, read_cmdline, which reads the
contents of /proc/self/cmdline into a heap-allocated buffer.
[BZ #18023]
* nscd/connections.c (read_cmdline): New function.
(restart): Use it. Update comment.
commit 9bed8b7fca7867d3027b66ce3985a75136aed013
Author: Florian Weimer <fweimer@redhat.com>
Date: Sun Mar 1 15:14:19 2015 +0100
getgrent_next_nss (compat-initgroups): Remove alloca fallback
If the caller-supplied buffer is not large enough, fall back directly
malloc.
The previous __libc_use_alloca check was incorrect because it did not
take into account that extend_alloca may fail to merge allocations, so
it would underestimate the stack space being used by roughly a factor
of two.
[BZ #18023]
* nis/nss_compat/compat-initgroups.c (getgrent_next_nss): Fall
back to malloc directly, without stack allocations.
commit c95cc759ecb21f812872934ac55518aef28cf46b
Author: Florian Weimer <fweimer@redhat.com>
Date: Sun Mar 1 16:03:01 2015 +0100
_dl_map_object_deps: Use struct scratch_buffer instead of extend_alloca
The function comment suggests that _dl_map_object_deps cannot use
malloc, but it already allocates the l_initfini array on the heap, so
the additional allocation should be acceptable.
[BZ #18023]
* elf/dl-deps.c (_dl_map_object_deps): Use struct
scratch_buffer instead of extend_alloca.
commit e38bff4db6f03d1fab732737f43a25160c3e4703
Author: Florian Weimer <fweimer@redhat.com>
Date: Sun Mar 1 16:18:21 2015 +0100
_nss_nis_initgroups_dyn: Use struct scratch_buffer instead of extend_alloca
Also adjusts the internal function get_uid.
[BZ #18023]
* nis/nss_nis/nis-initgroups.c (get_uid, _nss_nis_initgroups_dyn):
Use struct scratch_buffer instead of extend_alloca.
commit 8825d4709a686a870d313cc602d489ddd5354a08
Author: Florian Weimer <fweimer@redhat.com>
Date: Sun Mar 1 18:55:33 2015 +0100
nscd: Use struct scratch_buffer instead of extend_alloca in most caches
This replaces the ERANGE retry loops with loops which have heap
fallback. Heap allocation might actually be required for extremely
large NSS results.
[BZ #18023]
* nscd/grpcache.c (addgrbyX): Use struct scratch_buffer instead
of extend_alloca.
* nscd/hstcache.c (addhstbyX): Likewise.
* nscd/pwdcache.c (addpwbyX): Likewise.
* nscd/servicescache.c (addservbyX): Likewise.
commit 140d8711d446f5193b04b56e714ddf8d0eddbf62
Author: Florian Weimer <fweimer@redhat.com>
Date: Sun Mar 1 18:59:48 2015 +0100
nscd: Switch to struct scratch_buffer in adhstaiX
The pre-allocation of the three scratch buffers increased the initial
stack size somewhat, but if retries are needed, the previous version
used more stack space if extend_alloca could not merge allocations.
Lack of alloca accounting also means could be problematic with
extremely large NSS responses, too.
[BZ #18023]
* nscd/aicache.c (addhstaiX): Use struct scratch_buffer instead
of extend_alloca.
commit 1af14faef808f03276766e5ee6d9ee7dc9053fba
Author: Florian Weimer <fweimer@redhat.com>
Date: Sun Mar 1 19:03:01 2015 +0100
getent: Switch to struct scratch_buffer in initgroups_keys
The retry loop is slightly different here because getgrouplist
provides size information, so scratch_buffer_set_array_size can be
used to grow the buffer in a more precise fashion.
[BZ #18023]
* nss/getent.c (initgroups_keys): Use struct scratch_buffer
instead of extend_alloca.
commit 9b71d3b4df6dd4e49f7638d1d936c921c50fa3d9
Author: Florian Weimer <fweimer@redhat.com>
Date: Sun Mar 1 19:09:00 2015 +0100
nss_files: Use struct scratch_buffer instead of extend_alloca
In both _nss_files_gethostbyname3_r and _nss_files_initgroups_dyn,
__libc_use_alloca was misused because it was not taken into account
that extend_alloca can fail to merge allocations.
[BZ #18023]
* nss/nss_files/files-hosts.c (_nss_files_gethostbyname3_r):
Use struct scratch_buffer instead of extend_alloca.
* nss/nss_files/files-initgroups.c (_nss_files_initgroups_dyn):
Likewise.
commit 11c2a8bad9ca5fe510b73c0204b3dcf703f14d5c
Author: Florian Weimer <fweimer@redhat.com>
Date: Sun Mar 1 19:11:55 2015 +0100
gethostid (Linux variant): Switch to struct scratch_buffer
Previously, extend_alloca was used without alloca accounting,
which could have been problematic with large NSS results.
[BZ #18023]
* sysdeps/unix/sysv/linux/gethostid.c (gethostid): Use struct
scratch_buffer instead of extend_alloca.
commit 6de00dd8a3a76d0b7586393451e65ad6c2721a71
Author: Florian Weimer <fweimer@redhat.com>
Date: Sun Mar 1 19:14:29 2015 +0100
getlogin_r (Linux variant): Switch to struct scratch_buffer
This corrects the alloca accounting as a side effect. It was not off
if extend_alloca failed to merge allocations.
[BZ #18023]
* sysdeps/unix/sysv/linux/getlogin_r.c (__getlogin_r_loginuid):
Use struct scratch_buffer instead of extend_alloca.
commit 488063238ee5c87b66c6982b1b6d508e30e44386
Author: Florian Weimer <fweimer@redhat.com>
Date: Sun Mar 1 19:48:31 2015 +0100
wordexp: Rewrite parse_tilde to use struct scratch_buffer
[BZ #18023]
* posix/wordexp.c (parse_tilde): Use struct scratch_buffer
instead of extend_alloca.
commit 7b4c16db30304b83a5d1e913d1a8f7e90a8c398c
Author: Florian Weimer <fweimer@redhat.com>
Date: Sun Mar 1 19:49:50 2015 +0100
glob: Rewrite to use struct scratch_buffer instead of extend_alloca
[BZ #18023]
* posix/glob.c (glob): Use struct scratch_buffer instead of
extend_alloca.
commit 683543bbb3e2c1b17554c4096d00c2980f39a802
Author: Florian Weimer <fweimer@redhat.com>
Date: Sun Mar 1 23:22:45 2015 +0100
Remove macros extend_alloca, extend_alloca_account [BZ #18023]
And also the helper macro stackinfo_alloca_round.
extend_alloca simply does not work on x86_64 and current i386 because
its peculiar stack alignment rules.
Here's an analysis of the _dl_fini situation (before the removal of
extend_alloca).
Dump of assembler code for function _dl_fini:
<+0>: push %rbp
<+1>: mov %rsp,%rbp
<+4>: push %r15
<+6>: push %r14
<+8>: push %r13
<+10>: push %r12
<+12>: push %rbx
<+13>: sub $0x38,%rsp
The function pushes 6 registers on the stack and allocates 0x38 bytes,
which means that %rsp is a multiple of 16 after function prologue.
The initial alloca allocation does not change %rsp alignment:
<+210>: shr $0x4,%rcx
<+214>: shl $0x4,%rcx
<+218>: sub %rcx,%rsp
%r15 is the address of the previous stack allocation, it is used below.
This is the extend_alloca reallocation branch:
<+734>: add $0xf,%rdx
<+738>: and $0xfffffffffffffff0,%rdx
<+742>: lea 0x1e(%rdx),%rcx
<+746>: shr $0x4,%rcx
<+750>: shl $0x4,%rcx
<+754>: sub %rcx,%rsp
<+757>: lea 0xf(%rsp),%rcx
<+762>: and $0xfffffffffffffff0,%rcx
<+766>: lea (%rcx,%rdx,1),%rsi
<+770>: cmp %rsi,%r15
<+773>: je 0x7f963940b673 <_dl_fini+787>
<+775>: mov %rdx,-0x58(%rbp)
<+787>: add %rdx,-0x58(%rbp)
(a) %rdx, the new requested size, is rounded up to a multiple of 16
(+734, %+738), and the result is stored in %rdx@738.
(b) %rdx@738 + 31 is rounded down to a multiple of 16, the result is
stored in rcx@750 (+742, +746, +750). So %rcx@750 == %rdx@738 + 16.
(c) %rcx@750 bytes are allocated on the stack (+754). %rsp is rounded
upwards to a multiple of 16, result is stored in %rcx@762 (+757, +762).
This does not change the value of %rsp because it already was a multiple
of 16.
(d) %rsi@766 == %rcx@762 + %rdx@738 is compared against %r15. But this
comparison is always false because we allocated 16 extra bytes on the
stack in (b), which were reserved for the alignment in (c), but in fact
unused. We are left with a gap in stack usage, and the comparison is
always false.
(@XXX refers to register values after executing the instruction at
offset +XXX.)
If the alignment gap was actually used because of different alignment
for %rsp, then the comparison failure would still occur because the gap
would not have been added after this reallocation, but before the
previous allocation.
As a result, extend_alloca is never able to merge allocations. It also
turns out that the interface is difficult to use, especially in
cojunction with alloca account (which is rarely optional).
[BZ #18023]
* include/alloca.h (stackinfo_alloca_round, extend_alloca,
extend_alloca_account): Remove.
Index: b/elf/dl-deps.c
===================================================================
--- a/elf/dl-deps.c
+++ b/elf/dl-deps.c
@@ -27,6 +27,7 @@
#include <unistd.h>
#include <sys/param.h>
#include <ldsodefs.h>
+#include <scratch_buffer.h>
#include <dl-dst.h>
@@ -184,9 +185,8 @@ _dl_map_object_deps (struct link_map *ma
/* 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 *ma
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 *ma
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 *ma
}
out:
+ scratch_buffer_free (&needed_space);
+
if (errno == 0 && errno_saved != 0)
__set_errno (errno_saved);
Index: b/include/alloca.h
===================================================================
--- a/include/alloca.h
+++ b/include/alloca.h
@@ -23,57 +23,17 @@ libc_hidden_proto (__libc_alloca_cutoff)
#include <allocalim.h>
-#ifndef stackinfo_alloca_round
-# define stackinfo_alloca_round(l) (((l) + 15) & -16)
-#endif
-
-#if _STACK_GROWS_DOWN
-# define extend_alloca(buf, len, newlen) \
- (__typeof (buf)) ({ size_t __newlen = stackinfo_alloca_round (newlen); \
- char *__newbuf = __alloca (__newlen); \
- if (__newbuf + __newlen == (char *) (buf)) \
- len += __newlen; \
- else \
- len = __newlen; \
- __newbuf; })
-#elif _STACK_GROWS_UP
-# define extend_alloca(buf, len, newlen) \
- (__typeof (buf)) ({ size_t __newlen = stackinfo_alloca_round (newlen); \
- char *__newbuf = __alloca (__newlen); \
- char *__buf = (char *) (buf); \
- if (__buf + len == __newbuf) \
- { \
- len += __newlen; \
- __newbuf = __buf; \
- } \
- else \
- len = __newlen; \
- __newbuf; })
-#else
-# define extend_alloca(buf, len, newlen) \
- __alloca (((len) = (newlen)))
-#endif
-
#if defined stackinfo_get_sp && defined stackinfo_sub_sp
# define alloca_account(size, avar) \
({ void *old__ = stackinfo_get_sp (); \
void *m__ = __alloca (size); \
avar += stackinfo_sub_sp (old__); \
m__; })
-# define extend_alloca_account(buf, len, newlen, avar) \
- ({ void *old__ = stackinfo_get_sp (); \
- void *m__ = extend_alloca (buf, len, newlen); \
- avar += stackinfo_sub_sp (old__); \
- m__; })
#else
# define alloca_account(size, avar) \
({ size_t s__ = (size); \
avar += s__; \
__alloca (s__); })
-# define extend_alloca_account(buf, len, newlen, avar) \
- ({ size_t s__ = (newlen); \
- avar += s__; \
- extend_alloca (buf, len, s__); })
#endif
# endif /* !_ISOMAC */
Index: b/nis/nss_compat/compat-initgroups.c
===================================================================
--- 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 *buf
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 *buf
== 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 *buf
status = NSS_STATUS_NOTFOUND;
done:
- if (use_malloc)
+ if (tmpbuf != buffer)
free (tmpbuf);
}
Index: b/nis/nss_nis/nis-initgroups.c
===================================================================
--- a/nis/nss_nis/nis-initgroups.c
+++ b/nis/nss_nis/nis-initgroups.c
@@ -16,7 +16,6 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
-#include <alloca.h>
#include <ctype.h>
#include <errno.h>
#include <grp.h>
@@ -27,6 +26,7 @@
#include <rpcsvc/yp.h>
#include <rpcsvc/ypclnt.h>
#include <sys/param.h>
+#include <scratch_buffer.h>
#include "nss-nis.h"
#include <libnsl.h>
@@ -120,27 +120,30 @@ internal_getgrent_r (struct group *grp,
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 *use
}
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,21 @@ _nss_nis_initgroups_dyn (const char *use
if (status != NSS_STATUS_SUCCESS)
return status;
- tmpbuf = __alloca (buflen);
+ struct scratch_buffer tmpbuf;
+ scratch_buffer_init (&tmpbuf);
while (1)
{
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;
+ *errnop = errno;
+ goto done;
+ }
if (status != NSS_STATUS_SUCCESS)
{
@@ -331,6 +338,7 @@ done:
intern.start = intern.start->next;
free (intern.next);
}
+ scratch_buffer_free (&tmpbuf);
return status;
}
Index: b/nscd/aicache.c
===================================================================
--- a/nscd/aicache.c
+++ b/nscd/aicache.c
@@ -26,6 +26,7 @@
#include <unistd.h>
#include <sys/mman.h>
#include <resolv/res_hconf.h>
+#include <scratch_buffer.h>
#include "dbg_log.h"
#include "nscd.h"
@@ -112,10 +113,13 @@ addhstaiX (struct database_dyn *db, int
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;
@@ -128,6 +132,7 @@ addhstaiX (struct database_dyn *db, int
int status[2] = { NSS_STATUS_UNAVAIL, NSS_STATUS_UNAVAIL };
int naddrs = 0;
size_t addrslen = 0;
+
char *canon = NULL;
size_t canonlen;
@@ -142,12 +147,17 @@ addhstaiX (struct database_dyn *db, int
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)
@@ -225,41 +235,38 @@ addhstaiX (struct database_dyn *db, int
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)
@@ -285,13 +292,11 @@ addhstaiX (struct database_dyn *db, int
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
@@ -320,18 +325,20 @@ addhstaiX (struct database_dyn *db, int
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)
@@ -559,6 +566,10 @@ next_nip:
dh->usable = false;
}
+ scratch_buffer_free (&tmpbuf6);
+ scratch_buffer_free (&tmpbuf4);
+ scratch_buffer_free (&canonbuf);
+
return timeout;
}
Index: b/nscd/connections.c
===================================================================
--- a/nscd/connections.c
+++ b/nscd/connections.c
@@ -1353,64 +1353,83 @@ request from '%s' [%ld] not handled due
}
}
-
-/* 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)
- {
- dbg_log (_("\
-cannot open /proc/self/cmdline: %s; disabling paranoia mode"),
- strerror (errno));
-
- paranoia = 0;
- return;
+ if (fd < 0)
+ return NULL;
+ size_t current = 0;
+ size_t limit = 1024;
+ char *buffer = malloc (limit);
+ if (buffer == NULL)
+ {
+ 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
strerror (errno));
paranoia = 0;
+ free (cmdline);
return;
}
@@ -1438,6 +1458,7 @@ cannot change to old GID: %s; disabling
ignore_value (setuid (server_uid));
paranoia = 0;
+ free (cmdline);
return;
}
}
@@ -1455,6 +1476,7 @@ cannot change to old working directory:
ignore_value (setgid (server_gid));
}
paranoia = 0;
+ free (cmdline);
return;
}
@@ -1503,6 +1525,7 @@ cannot change to old working directory:
dbg_log (_("cannot change current working directory to \"/\": %s"),
strerror (errno));
paranoia = 0;
+ free (cmdline);
/* Reenable the databases. */
time_t now = time (NULL);
Index: b/nscd/grpcache.c
===================================================================
--- a/nscd/grpcache.c
+++ b/nscd/grpcache.c
@@ -16,7 +16,6 @@
You should have received a copy of the GNU General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>. */
-#include <alloca.h>
#include <assert.h>
#include <errno.h>
#include <error.h>
@@ -32,6 +31,7 @@
#include <sys/mman.h>
#include <sys/socket.h>
#include <stackinfo.h>
+#include <scratch_buffer.h>
#include "nscd.h"
#include "dbg_log.h"
@@ -448,12 +448,12 @@ addgrbyX (struct database_dyn *db, int f
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))
{
@@ -463,43 +463,24 @@ addgrbyX (struct database_dyn *db, int f
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;
}
Index: b/nscd/hstcache.c
===================================================================
--- a/nscd/hstcache.c
+++ b/nscd/hstcache.c
@@ -34,6 +34,7 @@
#include <arpa/nameser.h>
#include <sys/mman.h>
#include <stackinfo.h>
+#include <scratch_buffer.h>
#include "nscd.h"
#include "dbg_log.h"
@@ -463,11 +464,8 @@ addhstbyX (struct database_dyn *db, int
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
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;
}
Index: b/nscd/pwdcache.c
===================================================================
--- a/nscd/pwdcache.c
+++ b/nscd/pwdcache.c
@@ -16,7 +16,6 @@
You should have received a copy of the GNU General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>. */
-#include <alloca.h>
#include <assert.h>
#include <errno.h>
#include <error.h>
@@ -32,6 +31,7 @@
#include <sys/mman.h>
#include <sys/socket.h>
#include <stackinfo.h>
+#include <scratch_buffer.h>
#include "nscd.h"
#include "dbg_log.h"
@@ -426,12 +426,11 @@ addpwbyX (struct database_dyn *db, int f
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))
{
@@ -441,45 +440,26 @@ addpwbyX (struct database_dyn *db, int f
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;
}
Index: b/nscd/servicescache.c
===================================================================
--- a/nscd/servicescache.c
+++ b/nscd/servicescache.c
@@ -16,7 +16,6 @@
You should have received a copy of the GNU General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>. */
-#include <alloca.h>
#include <assert.h>
#include <errno.h>
#include <libintl.h>
@@ -25,6 +24,7 @@
#include <stdint.h>
#include <sys/mman.h>
#include <kernel-features.h>
+#include <scratch_buffer.h>
#include "nscd.h"
#include "dbg_log.h"
@@ -374,12 +374,11 @@ addservbyX (struct database_dyn *db, int
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
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;
}
Index: b/nss/getent.c
===================================================================
--- a/nss/getent.c
+++ b/nss/getent.c
@@ -39,6 +39,7 @@
#include <netinet/ether.h>
#include <netinet/in.h>
#include <sys/socket.h>
+#include <scratch_buffer.h>
/* Get libc version number. */
#include <version.h>
@@ -477,30 +478,34 @@ netgroup_keys (int number, char *key[])
static int
initgroups_keys (int number, char *key[])
{
- int ngrps = 100;
- size_t grpslen = ngrps * sizeof (gid_t);
- gid_t *grps = alloca (grpslen);
-
if (number == 0)
{
fprintf (stderr, _("Enumeration not supported on %s\n"), "initgroups");
return 3;
}
+ struct scratch_buffer tmpbuf;
+ scratch_buffer_init (&tmpbuf);
+
for (int i = 0; i < number; ++i)
{
+ ssize_t ngrps = tmpbuf.length / sizeof (gid_t);
int no = ngrps;
int n;
- while ((n = getgrouplist (key[i], -1, grps, &no)) == -1
+ while ((n = getgrouplist (key[i], -1, tmpbuf.data, &no)) == -1
&& no > ngrps)
{
- grps = extend_alloca (grps, grpslen, no * sizeof (gid_t));
- ngrps = no;
+ if (!scratch_buffer_set_array_size (&tmpbuf, no, sizeof (gid_t)))
+ {
+ fprintf (stderr, _("Could not allocate group list: %m\n"));
+ return 3;
+ }
}
if (n == -1)
return 1;
+ const gid_t *grps = tmpbuf.data;
printf ("%-21s", key[i]);
for (int j = 0; j < n; ++j)
if (grps[j] != -1)
@@ -508,6 +513,8 @@ initgroups_keys (int number, char *key[]
putchar_unlocked ('\n');
}
+ scratch_buffer_free (&tmpbuf);
+
return 0;
}
Index: b/nss/nss_files/files-hosts.c
===================================================================
--- a/nss/nss_files/files-hosts.c
+++ b/nss/nss_files/files-hosts.c
@@ -22,7 +22,7 @@
#include <arpa/nameser.h>
#include <netdb.h>
#include <resolv.h>
-
+#include <scratch_buffer.h>
/* Get implementation for some internal functions. */
#include "../resolv/mapv4v6addr.h"
@@ -145,15 +145,12 @@ _nss_files_gethostbyname3_r (const char
&& _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
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
}
}
- 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);
Index: b/nss/nss_files/files-initgroups.c
===================================================================
--- a/nss/nss_files/files-initgroups.c
+++ b/nss/nss_files/files-initgroups.c
@@ -16,7 +16,6 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
-#include <alloca.h>
#include <errno.h>
#include <grp.h>
#include <nss.h>
@@ -25,6 +24,7 @@
#include <sys/param.h>
#include <stdbool.h>
#include <stdlib.h>
+#include <scratch_buffer.h>
enum nss_status
_nss_files_initgroups_dyn (const char *user, gid_t group, long int *start,
@@ -46,9 +46,8 @@ _nss_files_initgroups_dyn (const char *u
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 *u
}
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 *u
out:
/* Free memory. */
- if (buffer_use_malloc)
- free (buffer);
+ scratch_buffer_free (&tmpbuf);
free (line);
fclose (stream);
Index: b/posix/glob.c
===================================================================
--- a/posix/glob.c
+++ b/posix/glob.c
@@ -27,6 +27,7 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
+#include <scratch_buffer.h>
/* Outcomment the following line for production quality code. */
/* #define NDEBUG 1 */
@@ -293,7 +294,7 @@ glob (const char *pattern, int flags, in
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)
@@ -650,33 +651,13 @@ glob (const char *pattern, int flags, in
{
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)
{
@@ -684,67 +665,37 @@ glob (const char *pattern, int flags, in
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;
}
@@ -865,57 +816,24 @@ glob (const char *pattern, int flags, in
{
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);
}
@@ -944,8 +862,7 @@ glob (const char *pattern, int flags, in
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;
}
@@ -957,13 +874,11 @@ glob (const char *pattern, int flags, in
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
Index: b/posix/wordexp.c
===================================================================
--- a/posix/wordexp.c
+++ b/posix/wordexp.c
@@ -17,7 +17,6 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
-#include <alloca.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
@@ -41,6 +40,7 @@
#include <wchar.h>
#include <wordexp.h>
#include <kernel-features.h>
+#include <scratch_buffer.h>
#include <libc-lock.h>
#include <_itoa.h>
@@ -308,12 +308,7 @@ parse_tilde (char **word, size_t *word_l
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_l
}
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_l
/* 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_l
*word = w_addstr (*word, word_length, max_length, user);
}
+ scratch_buffer_free (&tmpbuf);
+
*offset = i - 1;
}
return *word ? 0 : WRDE_NOSPACE;
Index: b/sysdeps/unix/sysv/linux/gethostid.c
===================================================================
--- a/sysdeps/unix/sysv/linux/gethostid.c
+++ b/sysdeps/unix/sysv/linux/gethostid.c
@@ -63,13 +63,12 @@ sethostid (long int id)
# include <sys/param.h>
# include <resolv/netdb.h>
# include <netinet/in.h>
+# include <scratch_buffer.h>
long int
gethostid (void)
{
char hostname[MAXHOSTNAMELEN + 1];
- size_t buflen;
- char *buffer;
struct hostent hostbuf, *hp;
int32_t id;
struct in_addr in;
@@ -94,23 +93,26 @@ gethostid (void)
/* This also fails. Return and arbitrary value. */
return 0;
- buflen = 1024;
- buffer = __alloca (buflen);
+ struct scratch_buffer tmpbuf;
+ scratch_buffer_init (&tmpbuf);
/* To get the IP address we need to know the host name. */
- while (__gethostbyname_r (hostname, &hostbuf, buffer, buflen, &hp, &herr)
- != 0
+ while (__gethostbyname_r (hostname, &hostbuf,
+ tmpbuf.data, tmpbuf.length, &hp, &herr) != 0
|| hp == NULL)
if (herr != NETDB_INTERNAL || errno != ERANGE)
- return 0;
+ {
+ scratch_buffer_free (&tmpbuf);
+ return 0;
+ }
else
- /* Enlarge buffer. */
- buffer = extend_alloca (buffer, buflen, 2 * buflen);
+ if (!scratch_buffer_grow (&tmpbuf))
+ return 0;
in.s_addr = 0;
memcpy (&in, hp->h_addr,
(int) sizeof (in) < hp->h_length ? (int) sizeof (in) : hp->h_length);
-
+ scratch_buffer_free (&tmpbuf);
/* For the return value to be not exactly the IP address we do some
bit fiddling. */
return (int32_t) (in.s_addr << 16 | in.s_addr >> 16);
Index: b/sysdeps/unix/sysv/linux/getlogin_r.c
===================================================================
--- a/sysdeps/unix/sysv/linux/getlogin_r.c
+++ b/sysdeps/unix/sysv/linux/getlogin_r.c
@@ -18,6 +18,7 @@
#include <pwd.h>
#include <unistd.h>
#include <not-cancel.h>
+#include <scratch_buffer.h>
#define STATIC static
static int getlogin_r_fd0 (char *name, size_t namesize);
@@ -54,28 +55,19 @@ __getlogin_r_loginuid (char *name, size_
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_
memcpy (name, pwd.pw_name, needed);
out:
- if (use_malloc)
- free (buf);
-
+ scratch_buffer_free (&tmpbuf);
return result;
}