Home | History | Annotate | Line # | Download | only in gen
t_siginfo.c revision 1.1
      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/resource.h>
     32 #include <sys/time.h>
     33 #include <sys/ucontext.h>
     34 #include <sys/wait.h>
     35 
     36 #include <assert.h>
     37 #include <signal.h>
     38 #include <stdio.h>
     39 #include <stdlib.h>
     40 #include <unistd.h>
     41 
     42 #ifndef __vax__
     43 #include <ieeefp.h>
     44 #endif
     45 
     46 /* for sigchild */
     47 pid_t child;
     48 int code;
     49 int status;
     50 
     51 /* for sigfpe */
     52 sig_atomic_t fltdiv_signalled = 0;
     53 sig_atomic_t intdiv_signalled = 0;
     54 
     55 static void
     56 sig_debug(int signo, siginfo_t *info, ucontext_t *ctx)
     57 {
     58 	unsigned int i;
     59 	mcontext_t *mc = &ctx->uc_mcontext;
     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(mc->__gregs); i++)
     78 			printf("uc_mcontext.greg[%d] 0x%lx\n", i,
     79 			    mc->__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=%d\n", info->si_utime);
    133 		printf("si_stime=%d\n", 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 	double d = strtod("0", NULL);
    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("%g\n", 1 / d);
    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