diff options
Diffstat (limited to 'libc')
| -rw-r--r-- | libc/inet/rpc/rcmd.c | 60 | ||||
| -rw-r--r-- | libc/sysdeps/linux/common/bits/uClibc_alloc.h | 26 | ||||
| -rw-r--r-- | libc/sysdeps/linux/common/getdents.c | 10 | ||||
| -rw-r--r-- | libc/sysdeps/linux/common/getdents64.c | 10 | 
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;  } | 
