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