Home | History | Annotate | Line # | Download | only in gen
t_siginfo.c revision 1.8.2.1
      1 /* $NetBSD: t_siginfo.c,v 1.8.2.1 2011/03/05 15:10:55 bouyer Exp $ */
      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 #include <atf-c/config.h>
     31 
     32 #include <sys/inttypes.h>
     33 #include <sys/resource.h>
     34 #include <sys/time.h>
     35 #include <sys/ucontext.h>
     36 #include <sys/wait.h>
     37 
     38 #include <assert.h>
     39 #include <signal.h>
     40 #include <stdio.h>
     41 #include <stdlib.h>
     42 #include <string.h>
     43 #include <unistd.h>
     44 #include <setjmp.h>
     45 
     46 #ifndef __vax__
     47 #include <ieeefp.h>
     48 #endif
     49 
     50 /* for sigchild */
     51 pid_t child;
     52 int code;
     53 int status;
     54 
     55 /* for sigfpe */
     56 sig_atomic_t fltdiv_signalled = 0;
     57 sig_atomic_t intdiv_signalled = 0;
     58 
     59 static void
     60 sig_debug(int signo, siginfo_t *info, ucontext_t *ctx)
     61 {
     62 	unsigned int i;
     63 
     64 	printf("%d %p %p\n", signo, info, ctx);
     65 	if (info != NULL) {
     66 		printf("si_signo=%d\n", info->si_signo);
     67 		printf("si_errno=%d\n", info->si_errno);
     68 		printf("si_code=%d\n", info->si_code);
     69 		printf("si_value.sival_int=%d\n", info->si_value.sival_int);
     70 	}
     71 	if (ctx != NULL) {
     72 		printf("uc_flags 0x%x\n", ctx->uc_flags);
     73 		printf("uc_link %p\n", ctx->uc_link);
     74 		for (i = 0; i < __arraycount(ctx->uc_sigmask.__bits); i++)
     75 			printf("uc_sigmask[%d] 0x%x\n", i,
     76 			    ctx->uc_sigmask.__bits[i]);
     77 		printf("uc_stack %p %lu 0x%x\n", ctx->uc_stack.ss_sp,
     78 		    (unsigned long)ctx->uc_stack.ss_size,
     79 		    ctx->uc_stack.ss_flags);
     80 		for (i = 0; i < __arraycount(ctx->uc_mcontext.__gregs); i++)
     81 			printf("uc_mcontext.greg[%d] 0x%lx\n", i,
     82 			    (long)ctx->uc_mcontext.__gregs[i]);
     83 	}
     84 }
     85 
     86 static void
     87 sigalrm_action(int signo, siginfo_t *info, void *ptr)
     88 {
     89 
     90 	sig_debug(signo, info, (ucontext_t *)ptr);
     91 
     92 	ATF_REQUIRE_EQ(info->si_signo, SIGALRM);
     93 	ATF_REQUIRE_EQ(info->si_code, SI_TIMER);
     94 	ATF_REQUIRE_EQ(info->si_value.sival_int, ITIMER_REAL);
     95 
     96 	atf_tc_pass();
     97 	/* NOTREACHED */
     98 }
     99 
    100 ATF_TC(sigalarm);
    101 
    102 ATF_TC_HEAD(sigalarm, tc)
    103 {
    104 
    105 	atf_tc_set_md_var(tc, "descr",
    106 	    "Checks that signal trampoline correctly calls SIGALRM handler");
    107 }
    108 
    109 ATF_TC_BODY(sigalarm, tc)
    110 {
    111 	struct sigaction sa;
    112 	sa.sa_flags = SA_SIGINFO;
    113 	sa.sa_sigaction = sigalrm_action;
    114 	sigemptyset(&sa.sa_mask);
    115 	sigaction(SIGALRM, &sa, NULL);
    116 	for (;;) {
    117 		alarm(1);
    118 		sleep(1);
    119 	}
    120 	atf_tc_fail("SIGALRM handler wasn't called");
    121 }
    122 
    123 static void
    124 sigchild_action(int signo, siginfo_t *info, void *ptr)
    125 {
    126 	if (info != NULL) {
    127 		printf("info=%p\n", info);
    128 		printf("ptr=%p\n", ptr);
    129 		printf("si_signo=%d\n", info->si_signo);
    130 		printf("si_errno=%d\n", info->si_errno);
    131 		printf("si_code=%d\n", info->si_code);
    132 		printf("si_uid=%d\n", info->si_uid);
    133 		printf("si_pid=%d\n", info->si_pid);
    134 		printf("si_status=%d\n", info->si_status);
    135 		printf("si_utime=%lu\n", (unsigned long int)info->si_utime);
    136 		printf("si_stime=%lu\n", (unsigned long int)info->si_stime);
    137 	}
    138 	ATF_REQUIRE_EQ(info->si_code, code);
    139 	ATF_REQUIRE_EQ(info->si_signo, SIGCHLD);
    140 	ATF_REQUIRE_EQ(info->si_uid, getuid());
    141 	ATF_REQUIRE_EQ(info->si_pid, child);
    142 	if (WIFEXITED(info->si_status))
    143 		ATF_REQUIRE_EQ(WEXITSTATUS(info->si_status), status);
    144 	else if (WIFSTOPPED(info->si_status))
    145 		ATF_REQUIRE_EQ(WSTOPSIG(info->si_status), status);
    146 	else if (WIFSIGNALED(info->si_status))
    147 		ATF_REQUIRE_EQ(WTERMSIG(info->si_status), status);
    148 }
    149 
    150 static void
    151 setchildhandler(void (*action)(int, siginfo_t *, void *))
    152 {
    153 	struct sigaction sa;
    154 	sa.sa_flags = SA_SIGINFO;
    155 	sa.sa_sigaction = action;
    156 	sigemptyset(&sa.sa_mask);
    157 	sigaction(SIGCHLD, &sa, NULL);
    158 }
    159 
    160 static void
    161 sigchild_setup(void)
    162 {
    163 	sigset_t set;
    164 	struct rlimit rlim;
    165 
    166 	(void)getrlimit(RLIMIT_CORE, &rlim);
    167 	rlim.rlim_cur = rlim.rlim_max;
    168 	(void)setrlimit(RLIMIT_CORE, &rlim);
    169 
    170 	setchildhandler(sigchild_action);
    171 	sigemptyset(&set);
    172 	sigaddset(&set, SIGCHLD);
    173 	sigprocmask(SIG_BLOCK, &set, NULL);
    174 }
    175 
    176 ATF_TC(sigchild_normal);
    177 ATF_TC_HEAD(sigchild_normal, tc)
    178 {
    179 
    180 	atf_tc_set_md_var(tc, "descr",
    181 	    "Checks that signal trampoline correctly calls SIGCHLD handler "
    182 	    "when child exits normally");
    183 }
    184 
    185 ATF_TC_BODY(sigchild_normal, tc)
    186 {
    187 	sigset_t set;
    188 
    189 	sigchild_setup();
    190 
    191 	status = 25;
    192 	code = CLD_EXITED;
    193 
    194 	switch ((child = fork())) {
    195 	case 0:
    196 		sleep(1);
    197 		exit(status);
    198 	case -1:
    199 		atf_tc_fail("fork failed");
    200 	default:
    201 		sigemptyset(&set);
    202 		sigsuspend(&set);
    203 	}
    204 }
    205 
    206 ATF_TC(sigchild_dump);
    207 ATF_TC_HEAD(sigchild_dump, tc)
    208 {
    209 
    210 	atf_tc_set_md_var(tc, "descr",
    211 	    "Checks that signal trampoline correctly calls SIGCHLD handler "
    212 	    "when child segfaults");
    213 }
    214 
    215 ATF_TC_BODY(sigchild_dump, tc)
    216 {
    217 	sigset_t set;
    218 
    219 	sigchild_setup();
    220 
    221 	status = SIGSEGV;
    222 	code = CLD_DUMPED;
    223 
    224 	switch ((child = fork())) {
    225 	case 0:
    226 		sleep(1);
    227 		*(long *)0 = 0;
    228 		atf_tc_fail("Child did not segfault");
    229 		/* NOTREACHED */
    230 	case -1:
    231 		atf_tc_fail("fork failed");
    232 	default:
    233 		sigemptyset(&set);
    234 		sigsuspend(&set);
    235 	}
    236 }
    237 
    238 ATF_TC(sigchild_kill);
    239 ATF_TC_HEAD(sigchild_kill, tc)
    240 {
    241 
    242 	atf_tc_set_md_var(tc, "descr",
    243 	    "Checks that signal trampoline correctly calls SIGCHLD handler "
    244 	    "when child is killed");
    245 }
    246 
    247 ATF_TC_BODY(sigchild_kill, tc)
    248 {
    249 	sigset_t set;
    250 
    251 	sigchild_setup();
    252 
    253 	status = SIGPIPE;
    254 	code = CLD_KILLED;
    255 
    256 	switch ((child = fork())) {
    257 	case 0:
    258 		sigemptyset(&set);
    259 		sigsuspend(&set);
    260 		break;
    261 	case -1:
    262 		atf_tc_fail("fork failed");
    263 	default:
    264 		kill(child, SIGPIPE);
    265 		sigemptyset(&set);
    266 		sigsuspend(&set);
    267 	}
    268 }
    269 
    270 static sigjmp_buf sigfpe_flt_env;
    271 static void
    272 sigfpe_flt_action(int signo, siginfo_t *info, void *ptr)
    273 {
    274 
    275 	sig_debug(signo, info, (ucontext_t *)ptr);
    276 
    277 	if (fltdiv_signalled++ != 0)
    278 		atf_tc_fail("FPE handler called more than once");
    279 
    280 	ATF_REQUIRE_EQ(info->si_signo, SIGFPE);
    281 	ATF_REQUIRE_EQ(info->si_code, FPE_FLTDIV);
    282 	ATF_REQUIRE_EQ(info->si_errno, 0);
    283 
    284 	siglongjmp(sigfpe_flt_env, 1);
    285 }
    286 
    287 ATF_TC(sigfpe_flt);
    288 ATF_TC_HEAD(sigfpe_flt, tc)
    289 {
    290 
    291 	atf_tc_set_md_var(tc, "descr",
    292 	    "Checks that signal trampoline correctly calls SIGFPE handler "
    293 	    "for floating div-by-zero");
    294 }
    295 
    296 ATF_TC_BODY(sigfpe_flt, tc)
    297 {
    298 	struct sigaction sa;
    299 	double d = strtod("0", NULL);
    300 
    301 	if (system("cpuctl identify 0 | grep -q QEMU") == 0)
    302 		atf_tc_skip("Test does not run correctly under qemu");
    303 	if (system("cpuctl identify 0 | grep -q "
    304 	    "'cpu0: Intel Pentium II (Klamath) (686-class), id 0x633'") == 0)
    305 		atf_tc_skip("Test does not run correctly under qemu "
    306 		    "(heuristic match)");
    307 	if (strcmp(atf_config_get("atf_arch"),"powerpc") == 0)
    308 		atf_tc_skip("Test not valid on powerpc");
    309 	if (sigsetjmp(sigfpe_flt_env, 0) == 0) {
    310 		sa.sa_flags = SA_SIGINFO;
    311 		sa.sa_sigaction = sigfpe_flt_action;
    312 		sigemptyset(&sa.sa_mask);
    313 		sigaction(SIGFPE, &sa, NULL);
    314 #ifndef __vax__
    315 		fpsetmask(FP_X_INV|FP_X_DZ|FP_X_OFL|FP_X_UFL|FP_X_IMP);
    316 #endif
    317 		printf("%g\n", 1 / d);
    318 	}
    319 	if (fltdiv_signalled == 0)
    320 		atf_tc_fail("FPE signal handler was not invoked");
    321 }
    322 
    323 static sigjmp_buf sigfpe_int_env;
    324 static void
    325 sigfpe_int_action(int signo, siginfo_t *info, void *ptr)
    326 {
    327 
    328 	sig_debug(signo, info, (ucontext_t *)ptr);
    329 
    330 	if (intdiv_signalled++ != 0)
    331 		atf_tc_fail("INTDIV handler called more than once");
    332 
    333 	ATF_REQUIRE_EQ(info->si_signo, SIGFPE);
    334 	if (info->si_code == FPE_FLTDIV)
    335 		atf_tc_expect_fail("PR port-i386/43655 : integer div-by-zero "
    336 		    "reports FPE_FLTDIV instead of FPE_INTDIV");
    337 	ATF_REQUIRE_EQ(info->si_code, FPE_INTDIV);
    338 	atf_tc_expect_pass();
    339 	ATF_REQUIRE_EQ(info->si_errno, 0);
    340 
    341 	siglongjmp(sigfpe_int_env, 1);
    342 }
    343 
    344 ATF_TC(sigfpe_int);
    345 ATF_TC_HEAD(sigfpe_int, tc)
    346 {
    347 
    348 	atf_tc_set_md_var(tc, "descr",
    349 	    "Checks that signal trampoline correctly calls SIGFPE handler "
    350 	    "for integer div-by-zero");
    351 }
    352 
    353 ATF_TC_BODY(sigfpe_int, tc)
    354 {
    355 	struct sigaction sa;
    356 	long l = strtol("0", NULL, 10);
    357 
    358 	if (strcmp(atf_config_get("atf_arch"),"powerpc") == 0)
    359 		atf_tc_skip("Test not valid on powerpc");
    360 	if (sigsetjmp(sigfpe_int_env, 0) == 0) {
    361 		sa.sa_flags = SA_SIGINFO;
    362 		sa.sa_sigaction = sigfpe_int_action;
    363 		sigemptyset(&sa.sa_mask);
    364 		sigaction(SIGFPE, &sa, NULL);
    365 #ifndef __vax__
    366 		fpsetmask(FP_X_INV|FP_X_DZ|FP_X_OFL|FP_X_UFL|FP_X_IMP);
    367 #endif
    368 		printf("%ld\n", 1 / l);
    369 	}
    370 	if (intdiv_signalled == 0)
    371 		atf_tc_fail("FPE signal handler was not invoked");
    372 }
    373 
    374 static void
    375 sigsegv_action(int signo, siginfo_t *info, void *ptr)
    376 {
    377 
    378 	sig_debug(signo, info, (ucontext_t *)ptr);
    379 
    380 	ATF_REQUIRE_EQ(info->si_signo, SIGSEGV);
    381 	ATF_REQUIRE_EQ(info->si_errno, 0);
    382 	ATF_REQUIRE_EQ(info->si_code, SEGV_MAPERR);
    383 	ATF_REQUIRE_EQ(info->si_addr, (void *)0);
    384 
    385 	atf_tc_pass();
    386 	/* NOTREACHED */
    387 }
    388 
    389 ATF_TC(sigsegv);
    390 ATF_TC_HEAD(sigsegv, tc)
    391 {
    392 
    393 	atf_tc_set_md_var(tc, "descr",
    394 	    "Checks that signal trampoline correctly calls SIGSEGV handler");
    395 }
    396 
    397 ATF_TC_BODY(sigsegv, tc)
    398 {
    399 	struct sigaction sa;
    400 
    401 	sa.sa_flags = SA_SIGINFO;
    402 	sa.sa_sigaction = sigsegv_action;
    403 	sigemptyset(&sa.sa_mask);
    404 	sigaction(SIGSEGV, &sa, NULL);
    405 
    406 	*(long *)0 = 0;
    407 	atf_tc_fail("Test did not fault as expected");
    408 }
    409 
    410 ATF_TP_ADD_TCS(tp)
    411 {
    412 
    413 	ATF_TP_ADD_TC(tp, sigalarm);
    414 	ATF_TP_ADD_TC(tp, sigchild_normal);
    415 	ATF_TP_ADD_TC(tp, sigchild_dump);
    416 	ATF_TP_ADD_TC(tp, sigchild_kill);
    417 	ATF_TP_ADD_TC(tp, sigfpe_flt);
    418 	ATF_TP_ADD_TC(tp, sigfpe_int);
    419 	ATF_TP_ADD_TC(tp, sigsegv);
    420 
    421 	return atf_no_error();
    422 }
    423