diff options
Diffstat (limited to 'libc/sysdeps/linux')
-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 |
3 files changed, 40 insertions, 6 deletions
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; } |