Home | History | Annotate | Line # | Download | only in gen
t_siginfo.c revision 1.54
      1 /* $NetBSD: t_siginfo.c,v 1.54 2024/09/04 02:20:49 rin 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 
     31 #include <sys/resource.h>
     32 #include <sys/sysctl.h>
     33 #include <sys/time.h>
     34 #include <sys/ucontext.h>
     35 #include <sys/wait.h>
     36 
     37 #include <assert.h>
     38 #include <float.h>
     39 #include <inttypes.h>
     40 #include <setjmp.h>
     41 #include <signal.h>
     42 #include <stdio.h>
     43 #include <stdlib.h>
     44 #include <string.h>
     45 #include <unistd.h>
     46 
     47 #include <fenv.h>
     48 #ifdef __HAVE_FENV
     49 #include <ieeefp.h>	/* only need for ARM Cortex/Neon hack */
     50 #elif defined(_FLOAT_IEEE754)
     51 #include <ieeefp.h>
     52 #endif
     53 
     54 #include "isqemu.h"
     55 
     56 #ifdef ENABLE_TESTS
     57 /* for sigbus */
     58 volatile char *addr;
     59 
     60 /* for sigchild */
     61 pid_t child;
     62 int code;
     63 int status;
     64 
     65 /* for sigfpe */
     66 sig_atomic_t fltdiv_signalled = 0;
     67 sig_atomic_t intdiv_signalled = 0;
     68 
     69 static void
     70 sig_debug(int signo, siginfo_t *info, ucontext_t *ctx)
     71 {
     72 	unsigned int i;
     73 
     74 	printf("%d %p %p\n", signo, info, ctx);
     75 	if (info != NULL) {
     76 		printf("si_signo=%d\n", info->si_signo);
     77 		printf("si_errno=%d\n", info->si_errno);
     78 		printf("si_code=%d\n", info->si_code);
     79 		printf("si_value.sival_int=%d\n", info->si_value.sival_int);
     80 	}
     81 	if (ctx != NULL) {
     82 		printf("uc_flags 0x%x\n", ctx->uc_flags);
     83 		printf("uc_link %p\n", ctx->uc_link);
     84 		for (i = 0; i < __arraycount(ctx->uc_sigmask.__bits); i++)
     85 			printf("uc_sigmask[%d] 0x%x\n", i,
     86 			    ctx->uc_sigmask.__bits[i]);
     87 		printf("uc_stack %p %lu 0x%x\n", ctx->uc_stack.ss_sp,
     88 		    (unsigned long)ctx->uc_stack.ss_size,
     89 		    ctx->uc_stack.ss_flags);
     90 		for (i = 0; i < __arraycount(ctx->uc_mcontext.__gregs); i++)
     91 			printf("uc_mcontext.greg[%d] 0x%lx\n", i,
     92 			    (long)ctx->uc_mcontext.__gregs[i]);
     93 	}
     94 }
     95 
     96 static void
     97 sigalrm_action(int signo, siginfo_t *info, void *ptr)
     98 {
     99 
    100 	sig_debug(signo, info, (ucontext_t *)ptr);
    101 
    102 	ATF_REQUIRE_EQ(info->si_signo, SIGALRM);
    103 	ATF_REQUIRE_EQ(info->si_code, SI_TIMER);
    104 	ATF_REQUIRE_EQ(info->si_value.sival_int, ITIMER_REAL);
    105 
    106 	atf_tc_pass();
    107 	/* NOTREACHED */
    108 }
    109 
    110 ATF_TC(sigalarm);
    111 
    112 ATF_TC_HEAD(sigalarm, tc)
    113 {
    114 
    115 	atf_tc_set_md_var(tc, "descr",
    116 	    "Checks that signal trampoline correctly calls SIGALRM handler");
    117 }
    118 
    119 ATF_TC_BODY(sigalarm, tc)
    120 {
    121 	struct sigaction sa;
    122 	sa.sa_flags = SA_SIGINFO;
    123 	sa.sa_sigaction = sigalrm_action;
    124 	sigemptyset(&sa.sa_mask);
    125 	sigaction(SIGALRM, &sa, NULL);
    126 	for (;;) {
    127 		alarm(1);
    128 		sleep(1);
    129 	}
    130 	atf_tc_fail("SIGALRM handler wasn't called");
    131 }
    132 
    133 static void
    134 sigchild_action(int signo, siginfo_t *info, void *ptr)
    135 {
    136 	if (info != NULL) {
    137 		printf("info=%p\n", info);
    138 		printf("ptr=%p\n", ptr);
    139 		printf("si_signo=%d\n", info->si_signo);
    140 		printf("si_errno=%d\n", info->si_errno);
    141 		printf("si_code=%d\n", info->si_code);
    142 		printf("si_uid=%d\n", info->si_uid);
    143 		printf("si_pid=%d\n", info->si_pid);
    144 		printf("si_status=%d\n", info->si_status);
    145 		printf("si_utime=%lu\n", (unsigned long int)info->si_utime);
    146 		printf("si_stime=%lu\n", (unsigned long int)info->si_stime);
    147 	}
    148 	ATF_REQUIRE_EQ(info->si_code, code);
    149 	ATF_REQUIRE_EQ(info->si_signo, SIGCHLD);
    150 	ATF_REQUIRE_EQ(info->si_uid, getuid());
    151 	ATF_REQUIRE_EQ(info->si_pid, child);
    152 	if (WIFEXITED(info->si_status))
    153 		ATF_REQUIRE_EQ(WEXITSTATUS(info->si_status), status);
    154 	else if (WIFSTOPPED(info->si_status))
    155 		ATF_REQUIRE_EQ(WSTOPSIG(info->si_status), status);
    156 	else if (WIFSIGNALED(info->si_status))
    157 		ATF_REQUIRE_EQ(WTERMSIG(info->si_status), status);
    158 }
    159 
    160 static void
    161 setchildhandler(void (*action)(int, siginfo_t *, void *))
    162 {
    163 	struct sigaction sa;
    164 	sa.sa_flags = SA_SIGINFO;
    165 	sa.sa_sigaction = action;
    166 	sigemptyset(&sa.sa_mask);
    167 	sigaction(SIGCHLD, &sa, NULL);
    168 }
    169 
    170 static void
    171 sigchild_setup(void)
    172 {
    173 	sigset_t set;
    174 	struct rlimit rlim;
    175 
    176 	(void)getrlimit(RLIMIT_CORE, &rlim);
    177 	rlim.rlim_cur = rlim.rlim_max;
    178 	(void)setrlimit(RLIMIT_CORE, &rlim);
    179 
    180 	setchildhandler(sigchild_action);
    181 	sigemptyset(&set);
    182 	sigaddset(&set, SIGCHLD);
    183 	sigprocmask(SIG_BLOCK, &set, NULL);
    184 }
    185 
    186 ATF_TC(sigchild_normal);
    187 ATF_TC_HEAD(sigchild_normal, tc)
    188 {
    189 
    190 	atf_tc_set_md_var(tc, "descr",
    191 	    "Checks that signal trampoline correctly calls SIGCHLD handler "
    192 	    "when child exits normally");
    193 }
    194 
    195 ATF_TC_BODY(sigchild_normal, tc)
    196 {
    197 	sigset_t set;
    198 
    199 	sigchild_setup();
    200 
    201 	status = 25;
    202 	code = CLD_EXITED;
    203 
    204 	switch ((child = fork())) {
    205 	case 0:
    206 		sleep(1);
    207 		exit(status);
    208 	case -1:
    209 		atf_tc_fail("fork failed");
    210 	default:
    211 		sigemptyset(&set);
    212 		sigsuspend(&set);
    213 	}
    214 }
    215 
    216 ATF_TC(sigchild_dump);
    217 ATF_TC_HEAD(sigchild_dump, tc)
    218 {
    219 
    220 	atf_tc_set_md_var(tc, "descr",
    221 	    "Checks that signal trampoline correctly calls SIGCHLD handler "
    222 	    "when child segfaults");
    223 }
    224 
    225 ATF_TC_BODY(sigchild_dump, tc)
    226 {
    227 	sigset_t set;
    228 
    229 	sigchild_setup();
    230 
    231 	status = SIGSEGV;
    232 	code = CLD_DUMPED;
    233 
    234 	switch ((child = fork())) {
    235 	case 0:
    236 		sleep(1);
    237 		*(volatile long *)0 = 0;
    238 		atf_tc_fail("Child did not segfault");
    239 		/* NOTREACHED */
    240 	case -1:
    241 		atf_tc_fail("fork failed");
    242 	default:
    243 		sigemptyset(&set);
    244 		sigsuspend(&set);
    245 	}
    246 }
    247 
    248 ATF_TC(sigchild_kill);
    249 ATF_TC_HEAD(sigchild_kill, tc)
    250 {
    251 
    252 	atf_tc_set_md_var(tc, "descr",
    253 	    "Checks that signal trampoline correctly calls SIGCHLD handler "
    254 	    "when child is killed");
    255 }
    256 
    257 ATF_TC_BODY(sigchild_kill, tc)
    258 {
    259 	sigset_t set;
    260 
    261 	sigchild_setup();
    262 
    263 	status = SIGPIPE;
    264 	code = CLD_KILLED;
    265 
    266 	switch ((child = fork())) {
    267 	case 0:
    268 		sigemptyset(&set);
    269 		sigsuspend(&set);
    270 		break;
    271 	case -1:
    272 		atf_tc_fail("fork failed");
    273 	default:
    274 		kill(child, SIGPIPE);
    275 		sigemptyset(&set);
    276 		sigsuspend(&set);
    277 	}
    278 }
    279 
    280 static sigjmp_buf sigfpe_flt_env;
    281 static void
    282 sigfpe_flt_action(int signo, siginfo_t *info, void *ptr)
    283 {
    284 
    285 	sig_debug(signo, info, (ucontext_t *)ptr);
    286 
    287 	if (fltdiv_signalled++ != 0)
    288 		atf_tc_fail("FPE handler called more than once");
    289 
    290 	ATF_REQUIRE_EQ(info->si_signo, SIGFPE);
    291 	ATF_REQUIRE_EQ(info->si_code, FPE_FLTDIV);
    292 	ATF_REQUIRE_EQ(info->si_errno, 0);
    293 
    294 	siglongjmp(sigfpe_flt_env, 1);
    295 }
    296 
    297 ATF_TC(sigfpe_flt);
    298 ATF_TC_HEAD(sigfpe_flt, tc)
    299 {
    300 
    301 	atf_tc_set_md_var(tc, "descr",
    302 	    "Checks that signal trampoline correctly calls SIGFPE handler "
    303 	    "for floating div-by-zero");
    304 }
    305 
    306 ATF_TC_BODY(sigfpe_flt, tc)
    307 {
    308 	struct sigaction sa;
    309 	volatile double d = strtod("0", NULL);
    310 
    311 	if (isQEMU())
    312 		atf_tc_skip("Test does not run correctly under QEMU");
    313 #if (__arm__ && !__SOFTFP__) || __aarch64__
    314 	/*
    315 	 * Some NEON fpus do not trap on IEEE 754 FP exceptions.
    316 	 * skip these tests if running on them and compiled for
    317 	 * hard float.
    318 	 */
    319 	if (0 == fpsetmask(fpsetmask(FP_X_INV)))
    320 		atf_tc_skip("FPU does not implement traps on FP exceptions");
    321 #elif defined __riscv__
    322 	atf_tc_skip("RISC-V does not support floating-point exception traps");
    323 #endif
    324 	if (sigsetjmp(sigfpe_flt_env, 0) == 0) {
    325 		sa.sa_flags = SA_SIGINFO;
    326 		sa.sa_sigaction = sigfpe_flt_action;
    327 		sigemptyset(&sa.sa_mask);
    328 		sigaction(SIGFPE, &sa, NULL);
    329 #ifdef __HAVE_FENV
    330 		feenableexcept(FE_ALL_EXCEPT);
    331 #elif defined(_FLOAT_IEEE754)
    332 		fpsetmask(FP_X_INV|FP_X_DZ|FP_X_OFL|FP_X_UFL|FP_X_IMP);
    333 #endif
    334 		printf("%g\n", 1 / d);
    335 	}
    336 	if (fltdiv_signalled == 0)
    337 		atf_tc_fail("FPE signal handler was not invoked");
    338 }
    339 
    340 static sigjmp_buf sigfpe_int_env;
    341 static void
    342 sigfpe_int_action(int signo, siginfo_t *info, void *ptr)
    343 {
    344 
    345 	sig_debug(signo, info, (ucontext_t *)ptr);
    346 
    347 	if (intdiv_signalled++ != 0)
    348 		atf_tc_fail("INTDIV handler called more than once");
    349 
    350 	ATF_REQUIRE_EQ(info->si_signo, SIGFPE);
    351 	ATF_REQUIRE_EQ(info->si_code, FPE_INTDIV);
    352 	atf_tc_expect_pass();
    353 	ATF_REQUIRE_EQ(info->si_errno, 0);
    354 
    355 	siglongjmp(sigfpe_int_env, 1);
    356 }
    357 
    358 ATF_TC(sigfpe_int);
    359 ATF_TC_HEAD(sigfpe_int, tc)
    360 {
    361 
    362 	atf_tc_set_md_var(tc, "descr",
    363 	    "Checks that signal trampoline correctly calls SIGFPE handler "
    364 	    "for integer div-by-zero (PR port-i386/43655)");
    365 }
    366 
    367 ATF_TC_BODY(sigfpe_int, tc)
    368 {
    369 	struct sigaction sa;
    370 
    371 #if defined(__aarch64__) || defined(__powerpc__) || defined(__sh3__) || \
    372     defined(__riscv__)
    373 	atf_tc_skip("Integer division by zero doesn't trap");
    374 #endif
    375 	if (sigsetjmp(sigfpe_int_env, 0) == 0) {
    376 		sa.sa_flags = SA_SIGINFO;
    377 		sa.sa_sigaction = sigfpe_int_action;
    378 		sigemptyset(&sa.sa_mask);
    379 		sigaction(SIGFPE, &sa, NULL);
    380 #ifdef __HAVE_FENV
    381 		feenableexcept(FE_ALL_EXCEPT);
    382 #elif defined(_FLOAT_IEEE754)
    383 		fpsetmask(FP_X_INV|FP_X_DZ|FP_X_OFL|FP_X_UFL|FP_X_IMP);
    384 #endif
    385 		/*
    386 		 * Do not use constant 1 here. GCC >= 12 optimizes
    387 		 * (1 / i) to (abs(i) == 1 ? i : 0), even for -O0.
    388 		 */
    389 		volatile long unity = strtol("1", NULL, 10),
    390 		     zero  = strtol("0", NULL, 10);
    391 		printf("%ld\n", unity / zero);
    392 	}
    393 	if (intdiv_signalled == 0)
    394 		atf_tc_fail("FPE signal handler was not invoked");
    395 }
    396 
    397 static void
    398 sigsegv_action(int signo, siginfo_t *info, void *ptr)
    399 {
    400 
    401 	sig_debug(signo, info, (ucontext_t *)ptr);
    402 
    403 	ATF_REQUIRE_EQ(info->si_signo, SIGSEGV);
    404 	ATF_REQUIRE_EQ(info->si_errno, 0);
    405 	ATF_REQUIRE_EQ(info->si_code, SEGV_MAPERR);
    406 	ATF_REQUIRE_EQ(info->si_addr, (void *)0);
    407 
    408 	atf_tc_pass();
    409 	/* NOTREACHED */
    410 }
    411 
    412 ATF_TC(sigsegv);
    413 ATF_TC_HEAD(sigsegv, tc)
    414 {
    415 
    416 	atf_tc_set_md_var(tc, "descr",
    417 	    "Checks that signal trampoline correctly calls SIGSEGV handler");
    418 }
    419 
    420 ATF_TC_BODY(sigsegv, tc)
    421 {
    422 	struct sigaction sa;
    423 
    424 	sa.sa_flags = SA_SIGINFO;
    425 	sa.sa_sigaction = sigsegv_action;
    426 	sigemptyset(&sa.sa_mask);
    427 	sigaction(SIGSEGV, &sa, NULL);
    428 
    429 	*(volatile long *)0 = 0;
    430 	atf_tc_fail("Test did not fault as expected");
    431 }
    432 
    433 static void
    434 sigbus_action(int signo, siginfo_t *info, void *ptr)
    435 {
    436 
    437 	printf("si_addr = %p\n", info->si_addr);
    438 	sig_debug(signo, info, (ucontext_t *)ptr);
    439 
    440 	ATF_REQUIRE_EQ(info->si_signo, SIGBUS);
    441 	ATF_REQUIRE_EQ(info->si_errno, 0);
    442 	ATF_REQUIRE_EQ(info->si_code, BUS_ADRALN);
    443 
    444 #if defined(__i386__) || defined(__x86_64__)
    445 	atf_tc_skip("x86 architecture does not correctly "
    446 	    "report the address where the unaligned access occurred");
    447 #endif
    448 	ATF_REQUIRE_EQ(info->si_addr, (volatile void *)addr);
    449 
    450 	atf_tc_pass();
    451 	/* NOTREACHED */
    452 }
    453 
    454 ATF_TC(sigbus_adraln);
    455 ATF_TC_HEAD(sigbus_adraln, tc)
    456 {
    457 
    458 	atf_tc_set_md_var(tc, "descr",
    459 	    "Checks that signal trampoline correctly calls SIGBUS handler "
    460 	    "for invalid address alignment");
    461 }
    462 
    463 ATF_TC_BODY(sigbus_adraln, tc)
    464 {
    465 	struct sigaction sa;
    466 
    467 #if defined(__alpha__) || defined(__arm__)
    468 	int rv, val;
    469 	size_t len = sizeof(val);
    470 	rv = sysctlbyname("machdep.unaligned_sigbus", &val, &len, NULL, 0);
    471 	ATF_REQUIRE(rv == 0);
    472 	if (val == 0)
    473 		atf_tc_skip("No SIGBUS signal for unaligned accesses");
    474 #endif
    475 
    476 #ifdef __powerpc__
    477 	/*
    478 	 * SIGBUS is not mandatory for powerpc; most processors (not all)
    479 	 * can deal with unaligned accesses.
    480 	 */
    481 	atf_tc_skip("SIGBUS signal for unaligned accesses is "
    482 	    "not mandatory for this architecture");
    483 #endif
    484 
    485 	/* m68k (except sun2) never issue SIGBUS (PR lib/49653),
    486 	 * same for armv8 or newer */
    487 #if (defined(__m68k__) && !defined(__mc68010__)) || \
    488     defined(__aarch64__) || \
    489     defined(__riscv__) || \
    490     defined(__vax__)
    491 	atf_tc_skip("No SIGBUS signal for unaligned accesses");
    492 #endif
    493 
    494 #if defined(__mips__)
    495 	/* no way of detecting if on GXemul, so disable everywhere for now */
    496 	atf_tc_skip("GXemul fails to trap unaligned accesses with "
    497 	    "correct ENTRYHI");
    498 #endif
    499 
    500 	sa.sa_flags = SA_SIGINFO;
    501 	sa.sa_sigaction = sigbus_action;
    502 	sigemptyset(&sa.sa_mask);
    503 	sigaction(SIGBUS, &sa, NULL);
    504 
    505 	/* Enable alignment checks for x86. 0x40000 is PSL_AC. */
    506 #if defined(__i386__)
    507 	__asm__("pushf; orl $0x40000, (%esp); popf");
    508 #elif defined(__amd64__)
    509 	__asm__("pushf; orl $0x40000, (%rsp); popf");
    510 #endif
    511 
    512 	addr = calloc(2, sizeof(int));
    513 	ATF_REQUIRE(addr != NULL);
    514 
    515 	if (isQEMU_TCG())
    516 		atf_tc_expect_fail("QEMU fails to trap unaligned accesses");
    517 
    518 	/* Force an unaligned access */
    519 	addr++;
    520 	printf("now trying to access unaligned address %p\n", addr);
    521 	ATF_REQUIRE_EQ(*(volatile int *)addr, 0);
    522 
    523 	atf_tc_fail("Test did not fault as expected");
    524 }
    525 
    526 #else
    527 ATF_TC(dummy);
    528 ATF_TC_HEAD(dummy, tc)
    529 {
    530 	atf_tc_set_md_var(tc, "descr", "A dummy test");
    531 }
    532 
    533 ATF_TC_BODY(dummy, tc)
    534 {
    535 
    536 	// Dummy, skipped
    537 	// The ATF framework requires at least a single defined test.
    538 }
    539 #endif
    540 
    541 ATF_TP_ADD_TCS(tp)
    542 {
    543 
    544 #ifdef ENABLE_TESTS
    545 	ATF_TP_ADD_TC(tp, sigalarm);
    546 	ATF_TP_ADD_TC(tp, sigchild_normal);
    547 	ATF_TP_ADD_TC(tp, sigchild_dump);
    548 	ATF_TP_ADD_TC(tp, sigchild_kill);
    549 	ATF_TP_ADD_TC(tp, sigfpe_flt);
    550 	ATF_TP_ADD_TC(tp, sigfpe_int);
    551 	ATF_TP_ADD_TC(tp, sigsegv);
    552 	ATF_TP_ADD_TC(tp, sigbus_adraln);
    553 #else
    554 	ATF_TP_ADD_TC(tp, dummy);
    555 #endif
    556 
    557 	return atf_no_error();
    558 }
    559