t_siginfo.c revision 1.4 1 /* $NetBSD */
2
3 /*-
4 * Copyright (c) 2010 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <atf-c.h>
30
31 #include <sys/inttypes.h>
32 #include <sys/resource.h>
33 #include <sys/time.h>
34 #include <sys/ucontext.h>
35 #include <sys/wait.h>
36
37 #include <assert.h>
38 #include <signal.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <unistd.h>
42
43 #ifndef __vax__
44 #include <ieeefp.h>
45 #endif
46
47 /* for sigchild */
48 pid_t child;
49 int code;
50 int status;
51
52 /* for sigfpe */
53 sig_atomic_t fltdiv_signalled = 0;
54 sig_atomic_t intdiv_signalled = 0;
55
56 static void
57 sig_debug(int signo, siginfo_t *info, ucontext_t *ctx)
58 {
59 unsigned int i;
60
61 printf("%d %p %p\n", signo, info, ctx);
62 if (info != NULL) {
63 printf("si_signo=%d\n", info->si_signo);
64 printf("si_errno=%d\n", info->si_errno);
65 printf("si_code=%d\n", info->si_code);
66 printf("si_value.sival_int=%d\n", info->si_value.sival_int);
67 }
68 if (ctx != NULL) {
69 printf("uc_flags 0x%x\n", ctx->uc_flags);
70 printf("uc_link %p\n", ctx->uc_link);
71 for (i = 0; i < __arraycount(ctx->uc_sigmask.__bits); i++)
72 printf("uc_sigmask[%d] 0x%x\n", i,
73 ctx->uc_sigmask.__bits[i]);
74 printf("uc_stack %p %lu 0x%x\n", ctx->uc_stack.ss_sp,
75 (unsigned long)ctx->uc_stack.ss_size,
76 ctx->uc_stack.ss_flags);
77 for (i = 0; i < __arraycount(ctx->uc_mcontext.__gregs); i++)
78 printf("uc_mcontext.greg[%d] 0x%lx\n", i,
79 (long)ctx->uc_mcontext.__gregs[i]);
80 }
81 }
82
83 static void
84 sigalrm_action(int signo, siginfo_t *info, void *ptr)
85 {
86
87 sig_debug(signo, info, (ucontext_t *)ptr);
88
89 ATF_REQUIRE_EQ(info->si_signo, SIGALRM);
90 ATF_REQUIRE_EQ(info->si_code, SI_TIMER);
91 ATF_REQUIRE_EQ(info->si_value.sival_int, ITIMER_REAL);
92
93 atf_tc_pass();
94 /* NOTREACHED */
95 }
96
97 ATF_TC(sigalarm);
98
99 ATF_TC_HEAD(sigalarm, tc)
100 {
101
102 atf_tc_set_md_var(tc, "descr",
103 "Checks that signal trampoline correctly calls SIGALRM handler");
104 }
105
106 ATF_TC_BODY(sigalarm, tc)
107 {
108 struct sigaction sa;
109 sa.sa_flags = SA_SIGINFO;
110 sa.sa_sigaction = sigalrm_action;
111 sigemptyset(&sa.sa_mask);
112 sigaction(SIGALRM, &sa, NULL);
113 for (;;) {
114 alarm(1);
115 sleep(1);
116 }
117 atf_tc_fail("SIGALRM handler wasn't called");
118 }
119
120 static void
121 sigchild_action(int signo, siginfo_t *info, void *ptr)
122 {
123 if (info != NULL) {
124 printf("info=%p\n", info);
125 printf("ptr=%p\n", ptr);
126 printf("si_signo=%d\n", info->si_signo);
127 printf("si_errno=%d\n", info->si_errno);
128 printf("si_code=%d\n", info->si_code);
129 printf("si_uid=%d\n", info->si_uid);
130 printf("si_pid=%d\n", info->si_pid);
131 printf("si_status=%d\n", info->si_status);
132 printf("si_utime=%lu\n", (unsigned long int)info->si_utime);
133 printf("si_stime=%lu\n", (unsigned long int)info->si_stime);
134 }
135 ATF_REQUIRE_EQ(info->si_code, code);
136 ATF_REQUIRE_EQ(info->si_signo, SIGCHLD);
137 ATF_REQUIRE_EQ(info->si_uid, getuid());
138 ATF_REQUIRE_EQ(info->si_pid, child);
139 if (WIFEXITED(info->si_status))
140 ATF_REQUIRE_EQ(WEXITSTATUS(info->si_status), status);
141 else if (WIFSTOPPED(info->si_status))
142 ATF_REQUIRE_EQ(WSTOPSIG(info->si_status), status);
143 else if (WIFSIGNALED(info->si_status))
144 ATF_REQUIRE_EQ(WTERMSIG(info->si_status), status);
145 }
146
147 static void
148 setchildhandler(void (*action)(int, siginfo_t *, void *))
149 {
150 struct sigaction sa;
151 sa.sa_flags = SA_SIGINFO;
152 sa.sa_sigaction = action;
153 sigemptyset(&sa.sa_mask);
154 sigaction(SIGCHLD, &sa, NULL);
155 }
156
157 static void
158 sigchild_setup(void)
159 {
160 sigset_t set;
161 struct rlimit rlim;
162
163 (void)getrlimit(RLIMIT_CORE, &rlim);
164 rlim.rlim_cur = rlim.rlim_max;
165 (void)setrlimit(RLIMIT_CORE, &rlim);
166
167 setchildhandler(sigchild_action);
168 sigemptyset(&set);
169 sigaddset(&set, SIGCHLD);
170 sigprocmask(SIG_BLOCK, &set, NULL);
171 }
172
173 ATF_TC(sigchild_normal);
174 ATF_TC_HEAD(sigchild_normal, tc)
175 {
176
177 atf_tc_set_md_var(tc, "descr",
178 "Checks that signal trampoline correctly calls SIGCHLD handler "
179 "when child exits normally");
180 }
181
182 ATF_TC_BODY(sigchild_normal, tc)
183 {
184 sigset_t set;
185
186 sigchild_setup();
187
188 status = 25;
189 code = CLD_EXITED;
190
191 switch ((child = fork())) {
192 case 0:
193 sleep(1);
194 exit(status);
195 case -1:
196 atf_tc_fail("fork failed");
197 default:
198 sigemptyset(&set);
199 sigsuspend(&set);
200 }
201 }
202
203 ATF_TC(sigchild_dump);
204 ATF_TC_HEAD(sigchild_dump, tc)
205 {
206
207 atf_tc_set_md_var(tc, "descr",
208 "Checks that signal trampoline correctly calls SIGCHLD handler "
209 "when child segfaults");
210 }
211
212 ATF_TC_BODY(sigchild_dump, tc)
213 {
214 sigset_t set;
215
216 sigchild_setup();
217
218 status = SIGSEGV;
219 code = CLD_DUMPED;
220
221 switch ((child = fork())) {
222 case 0:
223 sleep(1);
224 *(long *)0 = 0;
225 atf_tc_fail("Child did not segfault");
226 /* NOTREACHED */
227 case -1:
228 atf_tc_fail("fork failed");
229 default:
230 sigemptyset(&set);
231 sigsuspend(&set);
232 }
233 }
234
235 ATF_TC(sigchild_kill);
236 ATF_TC_HEAD(sigchild_kill, tc)
237 {
238
239 atf_tc_set_md_var(tc, "descr",
240 "Checks that signal trampoline correctly calls SIGCHLD handler "
241 "when child is killed");
242 }
243
244 ATF_TC_BODY(sigchild_kill, tc)
245 {
246 sigset_t set;
247
248 sigchild_setup();
249
250 status = SIGPIPE;
251 code = CLD_KILLED;
252
253 switch ((child = fork())) {
254 case 0:
255 sigemptyset(&set);
256 sigsuspend(&set);
257 break;
258 case -1:
259 atf_tc_fail("fork failed");
260 default:
261 kill(child, SIGPIPE);
262 sigemptyset(&set);
263 sigsuspend(&set);
264 }
265 }
266
267 static void
268 sigfpe_flt_action(int signo, siginfo_t *info, void *ptr)
269 {
270
271 sig_debug(signo, info, (ucontext_t *)ptr);
272
273 if (fltdiv_signalled++ != 0)
274 atf_tc_fail("FPE handler called more than once");
275
276 ATF_REQUIRE_EQ(info->si_signo, SIGFPE);
277 ATF_REQUIRE_EQ(info->si_code, FPE_FLTDIV);
278 ATF_REQUIRE_EQ(info->si_errno, 0);
279 }
280
281 ATF_TC(sigfpe_flt);
282 ATF_TC_HEAD(sigfpe_flt, tc)
283 {
284
285 atf_tc_set_md_var(tc, "descr",
286 "Checks that signal trampoline correctly calls SIGFPE handler "
287 "for floating div-by-zero");
288 }
289
290 ATF_TC_BODY(sigfpe_flt, tc)
291 {
292 struct sigaction sa;
293 double d = strtod("0", NULL);
294
295 sa.sa_flags = SA_SIGINFO;
296 sa.sa_sigaction = sigfpe_flt_action;
297 sigemptyset(&sa.sa_mask);
298 sigaction(SIGFPE, &sa, NULL);
299 #ifndef __vax__
300 fpsetmask(FP_X_INV|FP_X_DZ|FP_X_OFL|FP_X_UFL|FP_X_IMP);
301 #endif
302 printf("%g\n", 1 / d);
303 if (fltdiv_signalled == 0)
304 atf_tc_fail("FPE signal handler was not invoked");
305 }
306
307 static void
308 sigfpe_int_action(int signo, siginfo_t *info, void *ptr)
309 {
310
311 sig_debug(signo, info, (ucontext_t *)ptr);
312
313 if (intdiv_signalled++ != 0)
314 atf_tc_fail("INTDIV handler called more than once");
315
316 ATF_REQUIRE_EQ(info->si_signo, SIGFPE);
317 if (info->si_code == FPE_FLTDIV)
318 atf_tc_expect_fail("PR port-i386/43655 : integer div-by-zero "
319 "reports FPE_FLTDIV instead of FPE_INTDIV");
320 ATF_REQUIRE_EQ(info->si_code, FPE_INTDIV);
321 ATF_REQUIRE_EQ(info->si_errno, 0);
322 }
323
324 ATF_TC(sigfpe_int);
325 ATF_TC_HEAD(sigfpe_int, tc)
326 {
327
328 atf_tc_set_md_var(tc, "descr",
329 "Checks that signal trampoline correctly calls SIGFPE handler "
330 "for integer div-by-zero");
331 }
332
333 ATF_TC_BODY(sigfpe_int, tc)
334 {
335 struct sigaction sa;
336 long l = strtol("0", NULL, 10);
337
338 sa.sa_flags = SA_SIGINFO;
339 sa.sa_sigaction = sigfpe_int_action;
340 sigemptyset(&sa.sa_mask);
341 sigaction(SIGFPE, &sa, NULL);
342 #ifndef __vax__
343 fpsetmask(FP_X_INV|FP_X_DZ|FP_X_OFL|FP_X_UFL|FP_X_IMP);
344 #endif
345 printf("%ld\n", 1 / l);
346 if (intdiv_signalled == 0)
347 atf_tc_fail("FPE signal handler was not invoked");
348 }
349
350 static void
351 sigsegv_action(int signo, siginfo_t *info, void *ptr)
352 {
353
354 sig_debug(signo, info, (ucontext_t *)ptr);
355
356 ATF_REQUIRE_EQ(info->si_signo, SIGSEGV);
357 ATF_REQUIRE_EQ(info->si_errno, 0);
358 ATF_REQUIRE_EQ(info->si_code, SEGV_MAPERR);
359 ATF_REQUIRE_EQ(info->si_addr, (void *)0);
360
361 atf_tc_pass();
362 /* NOTREACHED */
363 }
364
365 ATF_TC(sigsegv);
366 ATF_TC_HEAD(sigsegv, tc)
367 {
368
369 atf_tc_set_md_var(tc, "descr",
370 "Checks that signal trampoline correctly calls SIGSEGV handler");
371 }
372
373 ATF_TC_BODY(sigsegv, tc)
374 {
375 struct sigaction sa;
376
377 sa.sa_flags = SA_SIGINFO;
378 sa.sa_sigaction = sigsegv_action;
379 sigemptyset(&sa.sa_mask);
380 sigaction(SIGSEGV, &sa, NULL);
381
382 *(long *)0 = 0;
383 atf_tc_fail("Test did not fault as expected");
384 }
385
386 ATF_TP_ADD_TCS(tp)
387 {
388
389 ATF_TP_ADD_TC(tp, sigalarm);
390 ATF_TP_ADD_TC(tp, sigchild_normal);
391 ATF_TP_ADD_TC(tp, sigchild_dump);
392 ATF_TP_ADD_TC(tp, sigchild_kill);
393 ATF_TP_ADD_TC(tp, sigfpe_flt);
394 ATF_TP_ADD_TC(tp, sigfpe_int);
395 ATF_TP_ADD_TC(tp, sigsegv);
396
397 return atf_no_error();
398 }
399