[RFC] new helper funcs for alloca/malloc with mmu/nommu

Mike Frysinger vapier at gentoo.org
Tue Jul 27 05:57:23 UTC 2010


The rpc rcmd code has some ugly ifdef mazes to handle mmu/nommu differences
just to select alloca or malloc.  Unify those with some helper macros in a
new header, and then convert the rcmd code over to it.

This is all geared towards fixing the getdents helper functions which only
use alloca() atm.  Now that we have helper functions, convert the getdents
functions over too.

Signed-off-by: Mike Frysinger <vapier at gentoo.org>
---
 libc/inet/rpc/rcmd.c                          |   60 ++++++-------------------
 libc/stdlib/malloc-standard/malloc.h          |   11 ++---
 libc/sysdeps/linux/common/bits/uClibc_alloc.h |   23 +++++++++
 libc/sysdeps/linux/common/getdents.c          |   10 +++-
 libc/sysdeps/linux/common/getdents64.c        |   10 +++-
 5 files changed, 55 insertions(+), 59 deletions(-)
 create mode 100644 libc/sysdeps/linux/common/bits/uClibc_alloc.h

diff --git a/libc/inet/rpc/rcmd.c b/libc/inet/rpc/rcmd.c
index 628c291..fb1bd93 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/stdlib/malloc-standard/malloc.h b/libc/stdlib/malloc-standard/malloc.h
index 7a2e66d..73d4b12 100644
--- a/libc/stdlib/malloc-standard/malloc.h
+++ b/libc/stdlib/malloc-standard/malloc.h
@@ -349,16 +349,13 @@ __UCLIBC_MUTEX_EXTERN(__malloc_lock);
 #endif
 
 #ifdef __ARCH_USE_MMU__
-
-#define MMAP(addr, size, prot) \
- (mmap((addr), (size), (prot), MAP_PRIVATE|MAP_ANONYMOUS, 0, 0))
-
+# define _MAP_UNINITIALIZE 0
 #else
+# define _MAP_UNINITIALIZE MAP_UNINITIALIZE
+#endif
 
 #define MMAP(addr, size, prot) \
- (mmap((addr), (size), (prot), MAP_SHARED|MAP_ANONYMOUS|MAP_UNINITIALIZE, 0, 0))
-
-#endif
+ (mmap((addr), (size), (prot), MAP_PRIVATE|MAP_ANONYMOUS|_MAP_UNINITIALIZE, 0, 0))
 
 
 /* -----------------------  Chunk representations ----------------------- */
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 0000000..0f13787
--- /dev/null
+++ b/libc/sysdeps/linux/common/bits/uClibc_alloc.h
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+#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 5dda190..46f7b8e 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 37cb4c6..30686f2 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;
 }
 
-- 
1.7.2



More information about the uClibc mailing list