0001
0002
0003
0004
0005
0006
0007
0008
0009 #undef NDEBUG
0010 #include <assert.h>
0011
0012 #include <err.h>
0013 #include <errno.h>
0014 #include <stdio.h>
0015 #include <signal.h>
0016 #include <stdlib.h>
0017 #include <string.h>
0018 #include <sys/resource.h>
0019 #include <sys/time.h>
0020 #include <sys/types.h>
0021 #include <sys/wait.h>
0022 #include <unistd.h>
0023
0024 #define _KB (1024)
0025 #define _MB (1024 * 1024)
0026
0027 volatile char *stack_top_ptr;
0028 volatile unsigned long stack_top_sp;
0029 volatile char c;
0030
0031 enum access_type {
0032 LOAD,
0033 STORE,
0034 };
0035
0036
0037
0038
0039
0040
0041 __attribute__ ((noinline))
0042 int consume_stack(unsigned long target_sp, unsigned long stack_high, int delta, enum access_type type)
0043 {
0044 unsigned long target;
0045 char stack_cur;
0046
0047 if ((unsigned long)&stack_cur > target_sp)
0048 return consume_stack(target_sp, stack_high, delta, type);
0049 else {
0050
0051
0052 stack_top_ptr = &stack_cur;
0053
0054 #ifdef __powerpc__
0055 asm volatile ("mr %[sp], %%r1" : [sp] "=r" (stack_top_sp));
0056 #else
0057 asm volatile ("mov %%rsp, %[sp]" : [sp] "=r" (stack_top_sp));
0058 #endif
0059 target = stack_high - delta + 1;
0060 volatile char *p = (char *)target;
0061
0062 if (type == STORE)
0063 *p = c;
0064 else
0065 c = *p;
0066
0067
0068
0069 getpid();
0070 }
0071
0072 return 0;
0073 }
0074
0075 static int search_proc_maps(char *needle, unsigned long *low, unsigned long *high)
0076 {
0077 unsigned long start, end;
0078 static char buf[4096];
0079 char name[128];
0080 FILE *f;
0081 int rc;
0082
0083 f = fopen("/proc/self/maps", "r");
0084 if (!f) {
0085 perror("fopen");
0086 return -1;
0087 }
0088
0089 while (fgets(buf, sizeof(buf), f)) {
0090 rc = sscanf(buf, "%lx-%lx %*c%*c%*c%*c %*x %*d:%*d %*d %127s\n",
0091 &start, &end, name);
0092 if (rc == 2)
0093 continue;
0094
0095 if (rc != 3) {
0096 printf("sscanf errored\n");
0097 rc = -1;
0098 break;
0099 }
0100
0101 if (strstr(name, needle)) {
0102 *low = start;
0103 *high = end - 1;
0104 rc = 0;
0105 break;
0106 }
0107 }
0108
0109 fclose(f);
0110
0111 return rc;
0112 }
0113
0114 int child(unsigned int stack_used, int delta, enum access_type type)
0115 {
0116 unsigned long low, stack_high;
0117
0118 assert(search_proc_maps("[stack]", &low, &stack_high) == 0);
0119
0120 assert(consume_stack(stack_high - stack_used, stack_high, delta, type) == 0);
0121
0122 printf("Access OK: %s delta %-7d used size 0x%06x stack high 0x%lx top_ptr %p top sp 0x%lx actual used 0x%lx\n",
0123 type == LOAD ? "load" : "store", delta, stack_used, stack_high,
0124 stack_top_ptr, stack_top_sp, stack_high - stack_top_sp + 1);
0125
0126 return 0;
0127 }
0128
0129 static int test_one(unsigned int stack_used, int delta, enum access_type type)
0130 {
0131 pid_t pid;
0132 int rc;
0133
0134 pid = fork();
0135 if (pid == 0)
0136 exit(child(stack_used, delta, type));
0137
0138 assert(waitpid(pid, &rc, 0) != -1);
0139
0140 if (WIFEXITED(rc) && WEXITSTATUS(rc) == 0)
0141 return 0;
0142
0143
0144 assert(!WIFEXITED(rc));
0145
0146 printf("Faulted: %s delta %-7d used size 0x%06x signal %d\n",
0147 type == LOAD ? "load" : "store", delta, stack_used,
0148 WTERMSIG(rc));
0149
0150 return 1;
0151 }
0152
0153
0154
0155 #define DEFAULT_SIZE (32 * _KB)
0156
0157 static void test_one_type(enum access_type type, unsigned long page_size, unsigned long rlim_cur)
0158 {
0159 unsigned long delta;
0160
0161
0162 for (delta = page_size; delta <= rlim_cur; delta += page_size)
0163 assert(test_one(DEFAULT_SIZE, delta, type) == 0);
0164
0165 assert(test_one(DEFAULT_SIZE, rlim_cur, type) == 0);
0166
0167
0168 assert(test_one(DEFAULT_SIZE, rlim_cur + 1, type) != 0);
0169 }
0170
0171 static int test(void)
0172 {
0173 unsigned long page_size;
0174 struct rlimit rlimit;
0175
0176 page_size = getpagesize();
0177 getrlimit(RLIMIT_STACK, &rlimit);
0178 printf("Stack rlimit is 0x%lx\n", rlimit.rlim_cur);
0179
0180 printf("Testing loads ...\n");
0181 test_one_type(LOAD, page_size, rlimit.rlim_cur);
0182 printf("Testing stores ...\n");
0183 test_one_type(STORE, page_size, rlimit.rlim_cur);
0184
0185 printf("All OK\n");
0186
0187 return 0;
0188 }
0189
0190 #ifdef __powerpc__
0191 #include "utils.h"
0192
0193 int main(void)
0194 {
0195 return test_harness(test, "stack_expansion_ldst");
0196 }
0197 #else
0198 int main(void)
0199 {
0200 return test();
0201 }
0202 #endif