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