/* * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved. * Copyright 2007, 2008 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code 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 General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. * */ // This is for anyone who wants to know where ia64 puts its guard pages #include #include #include #include #include typedef unsigned char *address; void fatal1(char *fmt, int res) { fprintf(stderr, fmt, res); fprintf(stderr, "\n"); exit(1); } void assert(int test, char *msg) { if (!test) { fprintf(stderr, "%s\n", msg); exit(1); } } #define align_size_up(size, alignment) \ (((size) + ((alignment) - 1)) & ~((alignment) - 1)) #define align_size_down(size, alignment) \ ((size) & ~((alignment) - 1)) static void current_stack_region() { pthread_attr_t attr; int res; res = pthread_getattr_np(pthread_self(), &attr); if (res != 0) { fatal1("pthread_getattr_np failed with errno = %d", res); } address stack_bottom; size_t stack_size; res = pthread_attr_getstack(&attr, (void **) &stack_bottom, &stack_size); if (res != 0) { fatal1("pthread_attr_getstack failed with errno = %d", res); } size_t page_size = sysconf(_SC_PAGESIZE); assert((intptr_t) stack_bottom == align_size_up((intptr_t) stack_bottom, page_size), "unaligned stack!"); size_t guard_size; res = pthread_attr_getguardsize(&attr, &guard_size); if (res != 0) { fatal1("pthread_attr_getguardsize failed with errno = %d", res); } assert(guard_size == align_size_up(guard_size, page_size), "unaligned guard!"); int total_pages = align_size_down(stack_size, page_size) / page_size; int guard_pages = align_size_up(guard_size, page_size) / page_size; address guard_bottom = stack_bottom + (total_pages - guard_pages) / 2 * page_size; address normal_stack_bottom = guard_bottom + guard_pages * page_size; fprintf(stderr, "stack pages %d, guard pages %d\n", total_pages, guard_pages); fprintf(stderr, "stack_bottom = %p\n", stack_bottom); fprintf(stderr, "guard_bottom = %p\n", guard_bottom); fprintf(stderr, "normal_stack_bottom = %p\n", normal_stack_bottom); address page; for (page = stack_bottom; page < stack_bottom+stack_size; page+=page_size) { char save; fprintf(stderr, "%p: ", page); if (page < guard_bottom || page >= normal_stack_bottom) { save = *page; *page = save; fprintf(stderr, "no bang\n"); } else { fprintf(stderr, "guard\n"); } } pthread_attr_destroy(&attr); } void *threadmain(void *arg) { current_stack_region(); return NULL; } void test(size_t stacksize, size_t guardsize) { pthread_attr_t attr; pthread_t tid; int res, arg; fprintf(stderr, "requesting %d stack and %d guard\n", stacksize, guardsize); res = pthread_attr_init(&attr); if (res != 0) { fatal1("pthread_attr_init failed with errno = %d", res); } res = pthread_attr_setstacksize(&attr, stacksize); if (res != 0) { fatal1("pthread_attr_setstacksize failed with errno = %d", res); } res = pthread_attr_setguardsize(&attr, guardsize); if (res != 0) { fatal1("pthread_attr_setguardsize failed with errno = %d", res); } res = pthread_create(&tid, &attr, threadmain, (void *) &arg); if (res != 0) { fatal1("pthread_create failed with errno = %d", res); } res = pthread_join(tid, NULL); if (res != 0) { fatal1("pthread_join failed with errno = %d", res); } pthread_attr_destroy(&attr); fprintf(stderr, "done\n\n"); } void segv_handler(int signum) { fprintf(stderr, "BANG!\n"); pthread_exit(NULL); } int main(int argc, char *argv[]) { int i, j; size_t page_size = sysconf(_SC_PAGESIZE); signal(SIGSEGV, segv_handler); for (i = 0; i < 8; i++) { for (j = 0; j < 4; j++) { test((100 + i) * (page_size / 4), j * page_size); } } }