xref: /netbsd-src/tests/lib/libc/gen/t_siginfo.c (revision 4817a0b0b8fe9612e8ebe21a9bf2d97b95038a97)
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