Handle FPE and BUS scenarios in the ATF t_trapsignal tests
These crash signals are crucial for proper handling of abnormal conditions in a program. The additional purpose of these tests it to assure the proper handling of these signals for the coming ptrace(2)-related changes in the signal routing code. Add a stub for ILL scenarios. All tests pass (on amd64). The shell ATF script contains duplicated code. There should be a way to deduplicate it, without rewrite to C. Sponsored by <The NetBSD Foundation>
This commit is contained in:
parent
b745c7b03f
commit
49994bfcd7
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: h_segv.c,v 1.4 2018/05/22 04:32:56 kamil Exp $ */
|
||||
/* $NetBSD: h_segv.c,v 1.5 2018/05/27 17:04:45 kamil Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2017 The NetBSD Foundation, Inc.
|
||||
@ -29,9 +29,10 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: h_segv.c,v 1.4 2018/05/22 04:32:56 kamil Exp $");
|
||||
__RCSID("$NetBSD: h_segv.c,v 1.5 2018/05/27 17:04:45 kamil Exp $");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@ -40,9 +41,6 @@ __RCSID("$NetBSD: h_segv.c,v 1.4 2018/05/22 04:32:56 kamil Exp $");
|
||||
#include <signal.h>
|
||||
#include <err.h>
|
||||
|
||||
// A faulting address
|
||||
static int *p = (int *) 0xfefefef0;
|
||||
|
||||
static int flags;
|
||||
#define F_RECURSE 1
|
||||
#define F_HANDLE 2
|
||||
@ -65,27 +63,107 @@ static struct {
|
||||
int v;
|
||||
} sn[] = {
|
||||
{ "segv", SIGSEGV },
|
||||
{ "trap", SIGTRAP }
|
||||
{ "trap", SIGTRAP },
|
||||
{ "ill", SIGILL },
|
||||
{ "fpe", SIGFPE },
|
||||
{ "bus", SIGBUS }
|
||||
};
|
||||
|
||||
static void
|
||||
trigger_segv(void)
|
||||
{
|
||||
volatile int *p = (int *)(intptr_t)atoi("0");
|
||||
|
||||
*p = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
trigger_trap(void)
|
||||
{
|
||||
|
||||
#ifdef PTRACE_BREAKPOINT_ASM
|
||||
PTRACE_BREAKPOINT_ASM;
|
||||
#else
|
||||
/* port me */
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
trigger_ill(void)
|
||||
{
|
||||
|
||||
#ifdef PTRACE_ILLEGAL_ASM
|
||||
PTRACE_ILLEGAL_ASM;
|
||||
#else
|
||||
/* port me */
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
trigger_fpe(void)
|
||||
{
|
||||
volatile int a = getpid();
|
||||
volatile int b = strtol("0", NULL, 0);
|
||||
|
||||
usleep(a/b);
|
||||
}
|
||||
|
||||
static void
|
||||
trigger_bus(void)
|
||||
{
|
||||
FILE *fp;
|
||||
char *p;
|
||||
|
||||
/* Open an empty file for writing. */
|
||||
fp = tmpfile();
|
||||
if (fp == NULL)
|
||||
err(EXIT_FAILURE, "tmpfile");
|
||||
|
||||
/* Map an empty file with mmap(2) to a pointer. */
|
||||
p = mmap(0, 1, PROT_WRITE, MAP_PRIVATE, fileno(fp), 0);
|
||||
if (p == MAP_FAILED)
|
||||
err(EXIT_FAILURE, "mmap");
|
||||
|
||||
/* Invalid memory access causes CPU trap, translated to SIGBUS */
|
||||
*p = 'a';
|
||||
}
|
||||
|
||||
static void
|
||||
trigger(void)
|
||||
{
|
||||
|
||||
switch (sig) {
|
||||
case SIGSEGV:
|
||||
trigger_segv();
|
||||
break;
|
||||
case SIGTRAP:
|
||||
trigger_trap();
|
||||
break;
|
||||
case SIGILL:
|
||||
trigger_ill();
|
||||
break;
|
||||
case SIGFPE:
|
||||
trigger_fpe();
|
||||
break;
|
||||
case SIGBUS:
|
||||
trigger_bus();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
foo(int s)
|
||||
{
|
||||
char buf[64];
|
||||
int i = snprintf(buf, sizeof(buf), "got %d\n", s);
|
||||
write(2, buf, i);
|
||||
if (flags & F_RECURSE) {
|
||||
if (sig == SIGSEGV)
|
||||
*p = 0;
|
||||
else if (sig == SIGTRAP) {
|
||||
#ifdef PTRACE_BREAKPOINT_ASM
|
||||
PTRACE_BREAKPOINT_ASM;
|
||||
#else
|
||||
/* port me */
|
||||
#endif
|
||||
}
|
||||
}
|
||||
exit(EXIT_SUCCESS);
|
||||
char buf[64];
|
||||
int i = snprintf(buf, sizeof(buf), "got %d\n", s);
|
||||
write(2, buf, i);
|
||||
|
||||
if (flags & F_RECURSE)
|
||||
trigger();
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
static __dead void
|
||||
@ -93,13 +171,16 @@ usage(void)
|
||||
{
|
||||
const char *pname = getprogname();
|
||||
|
||||
fprintf(stderr, "Usage: %s recurse|mask|handle|ignore ...\n", pname);
|
||||
fprintf(stderr, "Usage: %s segv|trap|ill|fpe|bus "
|
||||
"[recurse|mask|handle|ignore] ...\n", pname);
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
|
||||
if (argc == 1)
|
||||
usage();
|
||||
|
||||
@ -108,15 +189,20 @@ main(int argc, char *argv[])
|
||||
for (j = 0; j < __arraycount(nv); j++) {
|
||||
if (strcmp(nv[j].n, argv[i]) == 0) {
|
||||
flags |= nv[j].v;
|
||||
break;
|
||||
}
|
||||
if (strcmp(sn[j].n, argv[i]) == 0) {
|
||||
sig = sn[j].v;
|
||||
break;
|
||||
goto consumed;
|
||||
}
|
||||
}
|
||||
if (j == __arraycount(nv))
|
||||
usage();
|
||||
for (j = 0; j < __arraycount(sn); j++) {
|
||||
if (strcmp(sn[j].n, argv[i]) == 0) {
|
||||
sig = sn[j].v;
|
||||
goto consumed;
|
||||
}
|
||||
}
|
||||
|
||||
usage();
|
||||
|
||||
consumed:
|
||||
continue;
|
||||
}
|
||||
|
||||
if (flags == 0 || sig == 0)
|
||||
@ -151,14 +237,7 @@ main(int argc, char *argv[])
|
||||
err(EXIT_FAILURE, "sigaction");
|
||||
}
|
||||
|
||||
if (sig == SIGSEGV)
|
||||
*p = 1;
|
||||
else if (sig == SIGTRAP) {
|
||||
#ifdef PTRACE_BREAKPOINT_ASM
|
||||
PTRACE_BREAKPOINT_ASM;
|
||||
#else
|
||||
/* port me */
|
||||
#endif
|
||||
}
|
||||
trigger();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
# $NetBSD: t_trapsignal.sh,v 1.3 2018/05/22 04:32:56 kamil Exp $
|
||||
# $NetBSD: t_trapsignal.sh,v 1.4 2018/05/27 17:04:45 kamil Exp $
|
||||
#
|
||||
# Copyright (c) 2017 The NetBSD Foundation, Inc.
|
||||
# All rights reserved.
|
||||
@ -29,6 +29,9 @@
|
||||
#
|
||||
|
||||
HELPER=$(atf_get_srcdir)/h_segv
|
||||
|
||||
# SIGSEGV
|
||||
|
||||
atf_test_case segv_simple
|
||||
segv_simple()
|
||||
{
|
||||
@ -97,6 +100,8 @@ segv_ignore_body()
|
||||
${HELPER} segv ignore
|
||||
}
|
||||
|
||||
# SIGTRAP
|
||||
|
||||
atf_test_case trap_simple
|
||||
trap_simple()
|
||||
{
|
||||
@ -165,6 +170,146 @@ trap_ignore_body()
|
||||
${HELPER} trap ignore
|
||||
}
|
||||
|
||||
# SIGFPE
|
||||
|
||||
atf_test_case fpe_simple
|
||||
fpe_simple()
|
||||
{
|
||||
atf_set "descr" "Test unhandled SIGFPE with the right exit code"
|
||||
}
|
||||
fpe_simple_body()
|
||||
{
|
||||
atf_check -s signal:8 -o "inline:" -e "inline:" \
|
||||
${HELPER} fpe recurse
|
||||
}
|
||||
|
||||
atf_test_case fpe_handle
|
||||
fpe_handle()
|
||||
{
|
||||
atf_set "descr" "Test handled SIGFPE traps call the signal handler"
|
||||
}
|
||||
fpe_handle_body()
|
||||
{
|
||||
atf_check -s exit:0 -o "inline:" -e "inline:got 8\n" \
|
||||
${HELPER} fpe handle
|
||||
}
|
||||
|
||||
atf_test_case fpe_mask
|
||||
fpe_mask()
|
||||
{
|
||||
atf_set "descr" "Test that masking the trapped SIGFPE signal get reset"
|
||||
}
|
||||
fpe_mask_body()
|
||||
{
|
||||
atf_check -s signal:8 -o "inline:" -e "inline:" \
|
||||
${HELPER} fpe mask
|
||||
}
|
||||
|
||||
atf_test_case fpe_handle_mask
|
||||
fpe_handle_mask()
|
||||
{
|
||||
atf_set "descr" "Test handled and masked SIGFPE traps get reset"
|
||||
}
|
||||
fpe_handle_mask_body()
|
||||
{
|
||||
atf_check -s signal:8 -o "inline:" -e "inline:" \
|
||||
${HELPER} fpe mask handle
|
||||
}
|
||||
|
||||
atf_test_case fpe_handle_recurse
|
||||
fpe_handle_recurse()
|
||||
{
|
||||
atf_set "descr" "Test that receiving SIGFPE in the handler resets"
|
||||
}
|
||||
|
||||
fpe_handle_recurse_body()
|
||||
{
|
||||
atf_check -s signal:8 -o "inline:" -e "inline:got 8\n" \
|
||||
${HELPER} fpe handle recurse
|
||||
}
|
||||
|
||||
atf_test_case fpe_ignore
|
||||
fpe_ignore()
|
||||
{
|
||||
atf_set "descr" "Test ignored trap with right exit code"
|
||||
}
|
||||
|
||||
fpe_ignore_body()
|
||||
{
|
||||
atf_check -s signal:8 -o "inline:" -e "inline:" \
|
||||
${HELPER} fpe ignore
|
||||
}
|
||||
|
||||
# SIGBUS
|
||||
|
||||
atf_test_case bus_simple
|
||||
bus_simple()
|
||||
{
|
||||
atf_set "descr" "Test unhandled SIGBUS with the right exit code"
|
||||
}
|
||||
bus_simple_body()
|
||||
{
|
||||
atf_check -s signal:10 -o "inline:" -e "inline:" \
|
||||
${HELPER} bus recurse
|
||||
}
|
||||
|
||||
atf_test_case bus_handle
|
||||
bus_handle()
|
||||
{
|
||||
atf_set "descr" "Test handled SIGBUS traps call the signal handler"
|
||||
}
|
||||
bus_handle_body()
|
||||
{
|
||||
atf_check -s exit:0 -o "inline:" -e "inline:got 10\n" \
|
||||
${HELPER} bus handle
|
||||
}
|
||||
|
||||
atf_test_case bus_mask
|
||||
bus_mask()
|
||||
{
|
||||
atf_set "descr" "Test that masking the trapped SIGBUS signal get reset"
|
||||
}
|
||||
bus_mask_body()
|
||||
{
|
||||
atf_check -s signal:10 -o "inline:" -e "inline:" \
|
||||
${HELPER} bus mask
|
||||
}
|
||||
|
||||
atf_test_case bus_handle_mask
|
||||
bus_handle_mask()
|
||||
{
|
||||
atf_set "descr" "Test handled and masked SIGBUS traps get reset"
|
||||
}
|
||||
bus_handle_mask_body()
|
||||
{
|
||||
atf_check -s signal:10 -o "inline:" -e "inline:" \
|
||||
${HELPER} bus mask handle
|
||||
}
|
||||
|
||||
atf_test_case bus_handle_recurse
|
||||
bus_handle_recurse()
|
||||
{
|
||||
atf_set "descr" "Test that receiving SIGBUS in the handler resets"
|
||||
}
|
||||
|
||||
bus_handle_recurse_body()
|
||||
{
|
||||
atf_check -s signal:10 -o "inline:" -e "inline:got 10\n" \
|
||||
${HELPER} bus handle recurse
|
||||
}
|
||||
|
||||
atf_test_case bus_ignore
|
||||
bus_ignore()
|
||||
{
|
||||
atf_set "descr" "Test ignored trap with right exit code"
|
||||
}
|
||||
|
||||
bus_ignore_body()
|
||||
{
|
||||
atf_check -s signal:10 -o "inline:" -e "inline:" \
|
||||
${HELPER} bus ignore
|
||||
}
|
||||
|
||||
atf_init_test_cases()
|
||||
{
|
||||
atf_add_test_case segv_simple
|
||||
@ -178,4 +323,22 @@ atf_init_test_cases()
|
||||
atf_add_test_case trap_mask
|
||||
atf_add_test_case trap_handle_recurse
|
||||
atf_add_test_case trap_ignore
|
||||
|
||||
# atf_add_test_case ill_simple
|
||||
# atf_add_test_case ill_handle
|
||||
# atf_add_test_case ill_mask
|
||||
# atf_add_test_case ill_handle_recurse
|
||||
# atf_add_test_case ill_ignore
|
||||
|
||||
atf_add_test_case fpe_simple
|
||||
atf_add_test_case fpe_handle
|
||||
atf_add_test_case fpe_mask
|
||||
atf_add_test_case fpe_handle_recurse
|
||||
atf_add_test_case fpe_ignore
|
||||
|
||||
atf_add_test_case bus_simple
|
||||
atf_add_test_case bus_handle
|
||||
atf_add_test_case bus_mask
|
||||
atf_add_test_case bus_handle_recurse
|
||||
atf_add_test_case bus_ignore
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user