1/* 2 * Copyright (C) 2001 Jason Evans <jasone@freebsd.org>. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice(s), this list of conditions and the following disclaimer 10 * unmodified other than the allowable addition of one or more 11 * copyright notices. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice(s), this list of conditions and the following disclaimer in 14 * the documentation and/or other materials provided with the 15 * distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE 21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 27 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 * 29 * $FreeBSD$ 30 * 31 * Test thread stack guard functionality. 32 */ 33 34#include <assert.h> 35#include <stdio.h> 36#include <stdlib.h> 37#include <string.h> 38#include <errno.h> 39#include <limits.h> 40#include <pthread.h> 41 42#define FRAME_SIZE 1024 43#define FRAME_OVERHEAD 40 44 45struct args 46{ 47 void *top; /* Top of thread's initial stack frame. */ 48 int cur; /* Recursion depth. */ 49 int max; /* Maximum recursion depth. */ 50}; 51 52void * 53recurse(void *args) 54{ 55 int top; 56 struct args *parms = (struct args *)args; 57 char filler[FRAME_SIZE - FRAME_OVERHEAD]; 58 59 /* Touch the memory in this stack frame. */ 60 top = 0xa5; 61 memset(filler, 0xa5, sizeof(filler)); 62 63 if (parms->top == NULL) { 64 /* Initial stack frame. */ 65 parms->top = (void*)⊤ 66 } 67 68 /* 69 * Make sure frame size is what we expect. Getting this right involves 70 * hand tweaking, so just print a warning rather than aborting. 71 */ 72 if (parms->top - (void *)&top != FRAME_SIZE * parms->cur) { 73 fprintf(stderr, 74 "Stack size (%ld) != expected (%ld), frame %ld\n", 75 (long)parms->top - (long)&top, 76 (long)(FRAME_SIZE * parms->cur), (long)parms->cur); 77 } 78 79 parms->cur++; 80 if (parms->cur < parms->max) 81 recurse(args); 82 83 return NULL; 84} 85 86 87int 88main(int argc, char **argv) 89{ 90 size_t def_stacksize, def_guardsize; 91 size_t stacksize, guardsize; 92 pthread_t thread; 93 pthread_attr_t attr; 94 struct args args; 95 96 if (argc != 3) { 97 fprintf(stderr, "usage: guard_b <stacksize> <guardsize>\n"); 98 exit(1); 99 } 100 fprintf(stderr, "Test begin\n"); 101 102 stacksize = strtoul(argv[1], NULL, 10); 103 guardsize = strtoul(argv[2], NULL, 10); 104 105 assert(pthread_attr_init(&attr) == 0); 106 /* 107 * Exercise the attribute APIs more thoroughly than is strictly 108 * necessary for the meat of this test program. 109 */ 110 assert(pthread_attr_getstacksize(&attr, &def_stacksize) == 0); 111 assert(pthread_attr_getguardsize(&attr, &def_guardsize) == 0); 112 if (def_stacksize != stacksize) { 113 assert(pthread_attr_setstacksize(&attr, stacksize) == 0); 114 assert(pthread_attr_getstacksize(&attr, &def_stacksize) == 0); 115 assert(def_stacksize == stacksize); 116 } 117 if (def_guardsize != guardsize) { 118 assert(pthread_attr_setguardsize(&attr, guardsize) == 0); 119 assert(pthread_attr_getguardsize(&attr, &def_guardsize) == 0); 120 assert(def_guardsize >= guardsize); 121 } 122 123 /* 124 * Create a thread that will come just short of overflowing the thread 125 * stack. We need to leave a bit of breathing room in case the thread 126 * is context switched, and we also have to take care not to call any 127 * functions in the deepest stack frame. 128 */ 129 args.top = NULL; 130 args.cur = 0; 131 args.max = (stacksize / FRAME_SIZE) - 1; 132 fprintf(stderr, "No overflow:\n"); 133 assert(pthread_create(&thread, &attr, recurse, &args) == 0); 134 assert(pthread_join(thread, NULL) == 0); 135 136 /* 137 * Create a thread that will barely of overflow the thread stack. This 138 * should cause a segfault. 139 */ 140 args.top = NULL; 141 args.cur = 0; 142 args.max = (stacksize / FRAME_SIZE) + 1; 143 fprintf(stderr, "Overflow:\n"); 144 assert(pthread_create(&thread, &attr, recurse, &args) == 0); 145 assert(pthread_join(thread, NULL) == 0); 146 147 /* Not reached. */ 148 fprintf(stderr, "Unexpected success\n"); 149 abort(); 150 151 return 0; 152} 153