1 /* Licensed under Apache License v2.0 - see LICENSE file for details */
14 static __thread char ebuf[ALTSTACK_ERR_MAXLEN];
15 static __thread unsigned elen;
18 (elen += snprintf(ebuf + elen, sizeof(ebuf) - elen, \
19 "%s(altstack@%d) %s%s%s", \
20 elen ? "; " : "", __LINE__, (x), \
21 errno ? ": " : "", errno ? strerror(errno) : ""))
23 void altstack_perror(void)
25 fprintf(stderr, "%s\n", ebuf);
28 char *altstack_geterr(void)
33 static __thread jmp_buf jmp;
35 static void segvjmp(int signum)
40 static __thread void *rsp_save_[2];
41 static __thread rlim_t max_;
43 rlim_t altstack_max(void) {
47 static ptrdiff_t rsp_save(unsigned i) {
49 asm volatile ("movq %%rsp, %0" : "=g" (rsp_save_[i]));
50 return (char *) rsp_save_[0] - (char *) rsp_save_[i];
53 void altstack_rsp_save(void) {
57 ptrdiff_t altstack_used(void) {
61 static __thread void *(*fn_)(void *);
62 static __thread void *arg_, *out_;
64 int altstack(rlim_t max, void *(*fn)(void *), void *arg, void **out)
66 long pgsz = sysconf(_SC_PAGESIZE);
67 int ret = -1, undo = 0;
69 struct rlimit rl_save;
70 struct sigaction sa_save;
73 assert(max > 0 && fn);
74 #define ok(x, y) ({ long __r = (long) (x); if (__r == -1) { bang(#x); if (y) goto out; } __r; })
80 ebuf[elen = 0] = '\0';
83 // if the first page below the mapping is in use, we get max-pgsz usable bytes
84 // add pgsz to max to guarantee at least max usable bytes
87 ok(getrlimit(RLIMIT_STACK, &rl_save), 1);
88 ok(setrlimit(RLIMIT_STACK, &(struct rlimit) { max_, rl_save.rlim_max }), 1);
91 ok(m = mmap(0, max, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_GROWSDOWN|MAP_NORESERVE, -1, 0), 1);
94 if (setjmp(jmp) == 0) {
95 unsigned char sigstk[SIGSTKSZ];
96 stack_t ss = { .ss_sp = sigstk, .ss_size = sizeof(sigstk) };
97 struct sigaction sa = { .sa_handler = segvjmp, .sa_flags = SA_NODEFER|SA_RESETHAND|SA_ONSTACK };
99 ok(sigaltstack(&ss, 0), 1);
102 sigemptyset(&sa.sa_mask);
103 ok(sigaction(SIGSEGV, &sa, &sa_save), 1);
107 "mov %%rsp, %%r10\n\t"
111 : "=r" (rsp_save_[0]) : "0" (m + max) : "r10");
113 asm volatile ("pop %rsp");
115 if (out) *out = out_;
119 bang("SIGSEGV caught");
128 ok(sigaction(SIGSEGV, &sa_save, 0), 0);
130 ok(sigaltstack(&(stack_t) { .ss_flags = SS_DISABLE }, 0), 0);
132 ok(munmap(m, max), 0);
134 ok(setrlimit(RLIMIT_STACK, &rl_save), 0);
139 return !ret && elen ? 1 : ret;