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

Carmelo AMOROSO carmelo.amoroso at st.com
Tue Jul 27 06:02:07 UTC 2010


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 7/27/2010 7:57 AM, Mike Frysinger wrote:
> 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;
>  }
>  

Hi Mike,
do you think it could be extended to other part of the library ?

Cheers,
Carmelo
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (MingW32)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAkxOdl4ACgkQoRq/3BrK1s81TgCglNfFYvRx6ObYZTY5MeD7vbZn
yiQAnj287fuv2hADxfIiZe3WCeproPKm
=/V5k
-----END PGP SIGNATURE-----


More information about the uClibc mailing list