altstack: stack alignment and accounting tweaks
[ccan] / ccan / altstack / test / run.c
1 #include <assert.h>
2 #include <err.h>
3 #include <errno.h>
4 #include <setjmp.h>
5 #include <signal.h>
6 #include <string.h>
7 #include <unistd.h>
8 #include <sys/mman.h>
9 #include <ccan/tap/tap.h>
10 #include <ccan/altstack/altstack.h>
11 #define _XOPEN_SOURCE 700
12 #include <stdio.h>
13
14 enum {
15         getrlimit_      = 1<<0,
16         setrlimit_      = 1<<1,
17         mmap_           = 1<<2,
18         sigaltstack_    = 1<<3,
19         sigaction_      = 1<<4,
20         munmap_         = 1<<5,
21 };
22 int fail, call1, call2;
23 char *m_;
24 rlim_t msz_;
25 #define e(x) (900+(x))
26 #define seterr(x) (errno = e(x))
27 #define setcall(x) ((call1 |= !errno ? (x) : 0), (call2 |= errno || out_ ? (x) : 0))
28 #define getrlimit(...)          (fail&getrlimit_        ? (seterr(getrlimit_),          -1) : (setcall(getrlimit_),     getrlimit(__VA_ARGS__)))
29 #define mmap(...)               (fail&mmap_             ? (seterr(mmap_),       (void *)-1) : (setcall(mmap_),          mmap(__VA_ARGS__)))
30 #define munmap(a, b)            (fail&munmap_           ? (seterr(munmap_),             -1) : (setcall(munmap_),        munmap(m_=(a), msz_=(b))))
31 #define setrlimit(...)          (fail&setrlimit_        ? (seterr(setrlimit_),          -1) : (setcall(setrlimit_),     setrlimit(__VA_ARGS__)))
32 #define sigaltstack(...)        (fail&sigaltstack_      ? (seterr(sigaltstack_),        -1) : (setcall(sigaltstack_),   sigaltstack(__VA_ARGS__)))
33 #define sigaction(...)          (fail&sigaction_        ? (seterr(sigaction_),          -1) : (setcall(sigaction_),     sigaction(__VA_ARGS__)))
34
35 #define KiB (1024UL)
36 #define MiB (KiB*KiB)
37 #define GiB (MiB*KiB)
38 #define TiB (GiB*KiB)
39
40 FILE *mystderr;
41 #undef stderr
42 #define stderr mystderr
43 #undef ok
44 #include <ccan/altstack/altstack.c>
45 #undef ok
46
47 long used;
48
49 static void __attribute__((optimize("O0"))) dn(unsigned long i)
50 {
51         if (used) used = altstack_used();
52         if (i) dn(--i);
53 }
54 static void *wrap(void *i)
55 {
56         dn((unsigned long) i);
57         return wrap;
58 }
59
60 int main(void)
61 {
62         long pgsz = sysconf(_SC_PAGESIZE);
63
64         plan_tests(17);
65
66 #define chkfail(x, y, z, c1, c2) (call1 = 0, call2 = 0, errno = 0, ok1((fail = x) && (y) && errno == (z) && call1 == (c1) && call2 == (c2)));
67 #define   chkok(   y, z, c1, c2) (call1 = 0, call2 = 0, errno = 0, fail = 0,     ok1((y) && errno == (z) && call1 == (c1) && call2 == (c2)));
68
69         chkfail(getrlimit_,     altstack(8*MiB, wrap, 0, 0) == -1, e(getrlimit_),
70                 0,
71                 0);
72
73         chkfail(setrlimit_,     altstack(8*MiB, wrap, 0, 0) == -1, e(setrlimit_),
74                 getrlimit_,
75                 0);
76
77         chkfail(mmap_,          altstack(8*MiB, wrap, 0, 0) == -1, e(mmap_),
78                 getrlimit_|setrlimit_,
79                 setrlimit_);
80
81         chkfail(sigaltstack_,   altstack(8*MiB, wrap, 0, 0) == -1, e(sigaltstack_),
82                 getrlimit_|setrlimit_|mmap_,
83                 setrlimit_|munmap_);
84
85         chkfail(sigaction_,     altstack(8*MiB, wrap, 0, 0) == -1, e(sigaction_),
86                 getrlimit_|setrlimit_|mmap_|sigaltstack_,
87                 setrlimit_|munmap_|sigaltstack_);
88
89         chkfail(munmap_,        altstack(8*MiB, wrap, 0, 0) ==  1, e(munmap_),
90                 getrlimit_|setrlimit_|mmap_|sigaltstack_|sigaction_,
91                 setrlimit_|sigaltstack_|sigaction_);
92         if (fail = 0, munmap(m_, msz_) == -1)
93                 err(1, "munmap");
94
95         chkok(                  altstack(1*MiB, wrap, (void *) 1000000, 0) == -1, EOVERFLOW,
96                 getrlimit_|setrlimit_|mmap_|sigaltstack_|sigaction_,
97                 setrlimit_|munmap_|sigaltstack_|sigaction_);
98
99         // be sure segv catch is repeatable (SA_NODEFER)
100         chkok(                  altstack(1*MiB, wrap, (void *) 1000000, 0) == -1, EOVERFLOW,
101                 getrlimit_|setrlimit_|mmap_|sigaltstack_|sigaction_,
102                 setrlimit_|munmap_|sigaltstack_|sigaction_);
103
104         used = 1;
105         chkfail(munmap_,        altstack(1*MiB, wrap, (void *) 1000000, 0) == -1, EOVERFLOW,
106                 getrlimit_|setrlimit_|mmap_|sigaltstack_|sigaction_,
107                 setrlimit_|sigaltstack_|sigaction_);
108         if (fail = 0, munmap(m_, msz_) == -1)
109                 err(1, "munmap");
110
111         ok1(altstack_max() == 1*MiB);
112         diag("used: %lu", used);
113         ok1(used >= 1*MiB - pgsz && used <= 1*MiB + pgsz);
114
115         char *p;
116         for(p = altstack_geterr(); *p; p++)
117                 if (*p >= '0' && *p <= '9')
118                         *p = '~';
119
120         #define estr "(altstack@~~~) SIGSEGV caught; (altstack@~~~) munmap(m, max): Unknown error ~~~"
121         ok1(strcmp(altstack_geterr(), estr) == 0);
122
123         char buf[ALTSTACK_ERR_MAXLEN*2] = {0};
124         if ((mystderr = fmemopen(buf, sizeof(buf), "w")) == NULL)
125                 err(1, "fmemopen");
126
127         altstack_perror();
128         fflush(mystderr);
129         ok1(strcmp(buf, estr "\n") == 0);
130
131         used = 1;
132         chkok(                  altstack(8*MiB, wrap, (void *) 1000000, 0) == -1, EOVERFLOW,
133                 getrlimit_|setrlimit_|mmap_|sigaltstack_|sigaction_,
134                 setrlimit_|munmap_|sigaltstack_|sigaction_);
135
136         diag("used: %lu", used);
137         ok1(used >= 8*MiB - pgsz && used <= 8*MiB + pgsz);
138
139         used = 0;
140         chkok(                  altstack(8*MiB, wrap, (void *) 100000, 0) == 0, 0,
141                 getrlimit_|setrlimit_|mmap_|sigaltstack_|sigaction_|munmap_,
142                 setrlimit_|munmap_|sigaltstack_|sigaction_);
143
144         used = 1;
145         altstack_rsp_save();
146         dn(0);
147         diag("used: %lu", used);
148         ok1(used == 32 || used == 40);
149
150         return exit_status();
151 }