summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libc/inet/rpc/rcmd.c60
-rw-r--r--libc/sysdeps/linux/common/bits/uClibc_alloc.h26
-rw-r--r--libc/sysdeps/linux/common/getdents.c10
-rw-r--r--libc/sysdeps/linux/common/getdents64.c10
4 files changed, 54 insertions, 52 deletions
diff --git a/libc/inet/rpc/rcmd.c b/libc/inet/rpc/rcmd.c
index 628c291fe..fb1bd9320 100644
--- a/libc/inet/rpc/rcmd.c
+++ b/libc/inet/rpc/rcmd.c
@@ -69,7 +69,6 @@ static char sccsid[] = "@(#)rcmd.c 8.3 (Berkeley) 3/26/94";
#include <netinet/in.h>
#include <arpa/inet.h>
-#include <alloca.h>
#include <signal.h>
#include <fcntl.h>
#include <netdb.h>
@@ -86,6 +85,7 @@ static char sccsid[] = "@(#)rcmd.c 8.3 (Berkeley) 3/26/94";
#include <wchar.h>
#endif
#include <sys/uio.h>
+#include <bits/uClibc_alloc.h>
/* some forward declarations */
@@ -116,11 +116,7 @@ int rcmd(char **ahost, u_short rport, const char *locuser, const char *remuser,
#ifdef __UCLIBC_HAS_REENTRANT_RPC__
hstbuflen = 1024;
-#ifdef __ARCH_USE_MMU__
- tmphstbuf = alloca (hstbuflen);
-#else
- tmphstbuf = malloc (hstbuflen);
-#endif
+ tmphstbuf = stack_heap_alloc(hstbuflen);
while (gethostbyname_r (*ahost, &hostbuf, tmphstbuf,
hstbuflen, &hp, &herr) != 0 || hp == NULL)
@@ -128,9 +124,7 @@ int rcmd(char **ahost, u_short rport, const char *locuser, const char *remuser,
if (herr != NETDB_INTERNAL || errno != ERANGE)
{
__set_h_errno (herr);
-#ifndef __ARCH_USE_MMU__
- free(tmphstbuf);
-#endif
+ stack_heap_free(tmphstbuf);
herror(*ahost);
return -1;
}
@@ -138,17 +132,11 @@ int rcmd(char **ahost, u_short rport, const char *locuser, const char *remuser,
{
/* Enlarge the buffer. */
hstbuflen *= 2;
-#ifdef __ARCH_USE_MMU__
- tmphstbuf = alloca (hstbuflen);
-#else
- free(tmphstbuf);
- tmphstbuf = malloc (hstbuflen);
-#endif
+ stack_heap_free(tmphstbuf);
+ tmphstbuf = stack_heap_alloc(hstbuflen);
}
}
-#ifndef __ARCH_USE_MMU__
- free(tmphstbuf);
-#endif
+ stack_heap_free(tmphstbuf);
#else /* call the non-reentrant version */
if ((hp = gethostbyname(*ahost)) == NULL) {
return -1;
@@ -331,35 +319,23 @@ int ruserok(const char *rhost, int superuser, const char *ruser,
#ifdef __UCLIBC_HAS_REENTRANT_RPC__
buflen = 1024;
-#ifdef __ARCH_USE_MMU__
- buffer = alloca (buflen);
-#else
- buffer = malloc (buflen);
-#endif
+ buffer = stack_heap_alloc(buflen);
while (gethostbyname_r (rhost, &hostbuf, buffer,
buflen, &hp, &herr) != 0 || hp == NULL)
{
if (herr != NETDB_INTERNAL || errno != ERANGE) {
-#ifndef __ARCH_USE_MMU__
- free(buffer);
-#endif
+ stack_heap_free(buffer);
return -1;
} else
{
/* Enlarge the buffer. */
buflen *= 2;
-#ifdef __ARCH_USE_MMU__
- buffer = alloca (buflen);
-#else
- free(buffer);
- buffer = malloc (buflen);
-#endif
+ stack_heap_free(buffer);
+ buffer = stack_heap_alloc(buflen);
}
}
-#ifndef __ARCH_USE_MMU__
- free(buffer);
-#endif
+ stack_heap_free(buffer);
#else
if ((hp = gethostbyname(rhost)) == NULL) {
return -1;
@@ -452,23 +428,15 @@ iruserok2 (u_int32_t raddr, int superuser, const char *ruser, const char *luser,
#ifdef __UCLIBC_HAS_REENTRANT_RPC__
size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX);
struct passwd pwdbuf;
-#ifdef __ARCH_USE_MMU__
- char *buffer = alloca (buflen);
-#else
- char *buffer = malloc (buflen);
-#endif
+ char *buffer = stack_heap_alloc(buflen);
if (getpwnam_r (luser, &pwdbuf, buffer,
buflen, &pwd) != 0 || pwd == NULL)
{
-#ifndef __ARCH_USE_MMU__
- free(buffer);
-#endif
+ stack_heap_free(buffer);
return -1;
}
-#ifndef __ARCH_USE_MMU__
- free(buffer);
-#endif
+ stack_heap_free(buffer);
#else
if ((pwd = getpwnam(luser)) == NULL)
return -1;
diff --git a/libc/sysdeps/linux/common/bits/uClibc_alloc.h b/libc/sysdeps/linux/common/bits/uClibc_alloc.h
new file mode 100644
index 000000000..6a70d27b7
--- /dev/null
+++ b/libc/sysdeps/linux/common/bits/uClibc_alloc.h
@@ -0,0 +1,26 @@
+/*
+ * Macros to transparently switch between the stack and heap for large
+ * allocations. The former is useful on MMU systems as it results in
+ * smaller code, but the latter is required on NoMMU systems. This is
+ * due to small stacks that cannot grow and so doing large allocs will
+ * cause a stack overflow.
+ *
+ * Copyright (C) 2010 Mike Frysinger <vapier@gentoo.org>
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#ifndef _UCLIBC_ALLOC_H
+#define _UCLIBC_ALLOC_H
+
+#include <alloca.h>
+#include <stdlib.h>
+
+#ifdef __ARCH_USE_MMU__
+# define stack_heap_alloc(x) alloca(x)
+# define stack_heap_free(x) do { if (0) free(x); } while (0)
+#else
+# define stack_heap_alloc(x) malloc(x)
+# define stack_heap_free(x) free(x)
+#endif
+
+#endif
diff --git a/libc/sysdeps/linux/common/getdents.c b/libc/sysdeps/linux/common/getdents.c
index 5dda190a8..46f7b8e16 100644
--- a/libc/sysdeps/linux/common/getdents.c
+++ b/libc/sysdeps/linux/common/getdents.c
@@ -4,7 +4,6 @@
* Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
*/
-#include <alloca.h>
#include <assert.h>
#include <errno.h>
#include <dirent.h>
@@ -17,6 +16,7 @@
#include <sys/syscall.h>
#include <bits/kernel_types.h>
#include <bits/kernel-features.h>
+#include <bits/uClibc_alloc.h>
#if !(defined __UCLIBC_HAS_LFS__ && defined __NR_getdents64 && __WORDSIZE == 64)
/* If the condition above is met, __getdents is defined as an alias
@@ -93,11 +93,13 @@ ssize_t __getdents (int fd, char *buf, size_t nbytes)
nbytes - size_diff);
dp = (struct dirent *) buf;
- skdp = kdp = alloca (red_nbytes);
+ skdp = kdp = stack_heap_alloc(red_nbytes);
retval = __syscall_getdents(fd, (unsigned char *)kdp, red_nbytes);
- if (retval == -1)
+ if (retval == -1) {
+ stack_heap_free(skdp);
return -1;
+ }
while ((char *) kdp < (char *) skdp + retval) {
const size_t alignment = __alignof__ (struct dirent);
@@ -114,6 +116,7 @@ ssize_t __getdents (int fd, char *buf, size_t nbytes)
if ((char *) dp == buf) {
/* The buffer the user passed in is too small to hold even
one entry. */
+ stack_heap_free(skdp);
__set_errno (EINVAL);
return -1;
}
@@ -130,6 +133,7 @@ ssize_t __getdents (int fd, char *buf, size_t nbytes)
dp = (struct dirent *) ((char *) dp + new_reclen);
kdp = (struct kernel_dirent *) (((char *) kdp) + kdp->d_reclen);
}
+ stack_heap_free(skdp);
return (char *) dp - buf;
}
diff --git a/libc/sysdeps/linux/common/getdents64.c b/libc/sysdeps/linux/common/getdents64.c
index 37cb4c6f8..30686f25a 100644
--- a/libc/sysdeps/linux/common/getdents64.c
+++ b/libc/sysdeps/linux/common/getdents64.c
@@ -5,7 +5,6 @@
*/
#include <features.h>
-#include <alloca.h>
#include <assert.h>
#include <errno.h>
#include <dirent.h>
@@ -17,6 +16,7 @@
#include <sys/types.h>
#include <sys/syscall.h>
#include <bits/kernel_types.h>
+#include <bits/uClibc_alloc.h>
#if defined __UCLIBC_HAS_LFS__ && defined __NR_getdents64
@@ -52,11 +52,13 @@ ssize_t __getdents64 (int fd, char *buf, size_t nbytes)
nbytes - size_diff);
dp = (struct dirent64 *) buf;
- skdp = kdp = alloca (red_nbytes);
+ skdp = kdp = stack_heap_alloc(red_nbytes);
retval = __syscall_getdents64(fd, (unsigned char *)kdp, red_nbytes);
- if (retval == -1)
+ if (retval == -1) {
+ stack_heap_free(skdp);
return -1;
+ }
while ((char *) kdp < (char *) skdp + retval) {
const size_t alignment = __alignof__ (struct dirent64);
@@ -73,6 +75,7 @@ ssize_t __getdents64 (int fd, char *buf, size_t nbytes)
if ((char *) dp == buf) {
/* The buffer the user passed in is too small to hold even
one entry. */
+ stack_heap_free(skdp);
__set_errno (EINVAL);
return -1;
}
@@ -89,6 +92,7 @@ ssize_t __getdents64 (int fd, char *buf, size_t nbytes)
dp = (struct dirent64 *) ((char *) dp + new_reclen);
kdp = (struct kernel_dirent64 *) (((char *) kdp) + kdp->d_reclen);
}
+ stack_heap_free(skdp);
return (char *) dp - buf;
}