diff options
-rw-r--r-- | nptl/ChangeLog | 10 | ||||
-rw-r--r-- | nptl/Makefile | 2 | ||||
-rw-r--r-- | nptl/pthread_getattr_np.c | 9 | ||||
-rw-r--r-- | nptl/tst-pthread-getattr.c | 120 |
4 files changed, 139 insertions, 2 deletions
diff --git a/nptl/ChangeLog b/nptl/ChangeLog index 1ff8d978d0..f53c2f2824 100644 --- a/nptl/ChangeLog +++ b/nptl/ChangeLog @@ -1,3 +1,13 @@ +2012-06-20 Siddhesh Poyarekar <siddhesh@redhat.com> + + [BZ #12416] + * Makefile (tests): Add test case. + * pthread_getattr_np.c (pthread_getattr_np): Deduct pages below + the __libc_stack_end page from stacksize. Truncate stacksize to + make it page aligned when it is computed from RLIMIT_STACK. + * tst-pthread-getattr.c: New test case. Verify that stackaddr is + accessible. + 2012-06-07 Carlos Sánchez de La Lama <csanchezdll@gmail.com> [BZ #14205] diff --git a/nptl/Makefile b/nptl/Makefile index 2a36d01720..ef8e874cd8 100644 --- a/nptl/Makefile +++ b/nptl/Makefile @@ -245,7 +245,7 @@ tests = tst-typesizes \ tst-exec1 tst-exec2 tst-exec3 tst-exec4 \ tst-exit1 tst-exit2 tst-exit3 \ tst-stdio1 tst-stdio2 \ - tst-stack1 tst-stack2 tst-stack3 \ + tst-stack1 tst-stack2 tst-stack3 tst-pthread-getattr \ tst-unload \ tst-dlsym1 \ tst-sysconf \ diff --git a/nptl/pthread_getattr_np.c b/nptl/pthread_getattr_np.c index 75d717bb1f..7309185d14 100644 --- a/nptl/pthread_getattr_np.c +++ b/nptl/pthread_getattr_np.c @@ -120,8 +120,15 @@ pthread_getattr_np (thread_id, attr) && (uintptr_t) __libc_stack_end < to) { /* Found the entry. Now we have the info we need. */ - iattr->stacksize = rl.rlim_cur; iattr->stackaddr = stack_end; + iattr->stacksize = + rl.rlim_cur - (size_t) (to - (uintptr_t) stack_end); + + /* Cut it down to align it to page size since otherwise we + risk going beyond rlimit when the kernel rounds up the + stack extension request. */ + iattr->stacksize = (iattr->stacksize + & -(intptr_t) GLRO(dl_pagesize)); /* The limit might be too high. */ if ((size_t) iattr->stacksize diff --git a/nptl/tst-pthread-getattr.c b/nptl/tst-pthread-getattr.c new file mode 100644 index 0000000000..6f2cfc6514 --- /dev/null +++ b/nptl/tst-pthread-getattr.c @@ -0,0 +1,120 @@ +/* Make sure that the stackaddr returned by pthread_getattr_np is + reachable. + + Copyright (C) 2012 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <stdio.h> +#include <string.h> +#include <sys/resource.h> +#include <pthread.h> +#include <alloca.h> + +/* Move the stack pointer so that stackaddr is accessible and then check if it + really is accessible. This will segfault if it fails. */ +static void +allocate_and_test (void *stackaddr) +{ + void *mem = &mem; + /* FIXME: The difference will be negative for _STACK_GROWSUP. */ + mem = alloca ((size_t) (mem - stackaddr)); + *(int *)(mem) = 0; +} + +static int +get_self_pthread_attr (const char *id, void **stackaddr, size_t *stacksize) +{ + pthread_attr_t attr; + int ret; + pthread_t me = pthread_self (); + + if ((ret = pthread_getattr_np (me, &attr))) + { + printf ("%s: pthread_getattr_np failed: %s\n", id, strerror (ret)); + return 1; + } + + if ((ret = pthread_attr_getstack (&attr, stackaddr, stacksize))) + { + printf ("%s: pthread_attr_getstack returned error: %s\n", id, + strerror (ret)); + return 1; + } + + return 0; +} + +/* Verify that the stack size returned by pthread_getattr_np is usable when + the returned value is subject to rlimit. */ +static int +check_stack_top (void) +{ + struct rlimit stack_limit; + void *stackaddr; + size_t stacksize = 0; + int ret; + + puts ("Verifying that stack top is accessible"); + + ret = getrlimit (RLIMIT_STACK, &stack_limit); + if (ret) + { + perror ("getrlimit failed"); + return 1; + } + + if (get_self_pthread_attr ("check_stack_top", &stackaddr, &stacksize)) + return 1; + + /* Reduce the rlimit to a page less that what is currently being returned so + that we ensure that pthread_getattr_np uses rlimit. The figure is + intentionally unaligned so to verify that pthread_getattr_np returns an + aligned stacksize that correctly fits into the rlimit. We don't bother + about the case where the stack is limited by the vma below it and not by + the rlimit because the stacksize returned in that case is computed from + the end of that vma and is hence safe. */ + stack_limit.rlim_cur = stacksize - 4095; + printf ("Adjusting RLIMIT_STACK to %zu\n", stack_limit.rlim_cur); + if ((ret = setrlimit (RLIMIT_STACK, &stack_limit))) + { + perror ("setrlimit failed"); + return 1; + } + + if (get_self_pthread_attr ("check_stack_top2", &stackaddr, &stacksize)) + return 1; + + printf ("Adjusted rlimit: stacksize=%zu, stackaddr=%p\n", stacksize, + stackaddr); + allocate_and_test (stackaddr); + + puts ("Stack top tests done"); + + return 0; +} + +/* TODO: Similar check for thread stacks once the thread stack sizes are + fixed. */ +static int +do_test (void) +{ + return check_stack_top (); +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" |