Commit 0b6ee30e authored by Henrik Gramner's avatar Henrik Gramner

checkasm: Try to handle crashes more gracefully

Attempt to catch SIGFPE, SIGILL, and SIGSEGV and flag the current test as
failed instead of aborting abruptly.
parent 02312cae
......@@ -44,6 +44,7 @@ static unsigned get_seed(void) {
}
#else
#include <unistd.h>
#include <signal.h>
#include <sys/time.h>
#define COLOR_RED 1
#define COLOR_GREEN 2
......@@ -400,6 +401,44 @@ static CheckasmFunc *get_func(CheckasmFunc **root, const char *const name) {
return f;
}
checkasm_context checkasm_context_buf;
/* Crash handling: attempt to catch crashes and handle them
* gracefully instead of just aborting abruptly. */
#ifdef _WIN32
static LONG NTAPI signal_handler(EXCEPTION_POINTERS *const e) {
switch (e->ExceptionRecord->ExceptionCode) {
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
case EXCEPTION_INT_DIVIDE_BY_ZERO:
checkasm_fail_func("fatal arithmetic error");
break;
case EXCEPTION_ILLEGAL_INSTRUCTION:
case EXCEPTION_PRIV_INSTRUCTION:
checkasm_fail_func("illegal instruction");
break;
case EXCEPTION_ACCESS_VIOLATION:
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
case EXCEPTION_DATATYPE_MISALIGNMENT:
case EXCEPTION_IN_PAGE_ERROR:
case EXCEPTION_STACK_OVERFLOW:
checkasm_fail_func("segmentation fault");
break;
default:
return EXCEPTION_CONTINUE_SEARCH;
}
checkasm_load_context();
return EXCEPTION_CONTINUE_EXECUTION; /* never reached, but shuts up gcc */
}
#else
static void signal_handler(const int s) {
checkasm_set_signal_handler_state(0);
checkasm_fail_func(s == SIGFPE ? "fatal arithmetic error" :
s == SIGILL ? "illegal instruction" :
"segmentation fault");
checkasm_load_context();
}
#endif
/* Perform tests and benchmarks for the specified
* cpu flag if supported by the host */
static void check_cpu_flag(const char *const name, unsigned flag) {
......@@ -605,3 +644,17 @@ void checkasm_report(const char *const name, ...) {
max_length = length;
}
}
void checkasm_set_signal_handler_state(const int enabled) {
#ifdef _WIN32
if (enabled)
AddVectoredExceptionHandler(0, signal_handler);
else
RemoveVectoredExceptionHandler(signal_handler);
#else
void (*const handler)(int) = enabled ? signal_handler : SIG_DFL;
signal(SIGFPE, handler);
signal(SIGILL, handler);
signal(SIGSEGV, handler);
#endif
}
......@@ -33,6 +33,20 @@
#include <stdint.h>
#include <stdlib.h>
#if ARCH_X86_64 && defined(_WIN32)
/* setjmp/longjmp on 64-bit Windows will try to use SEH to unwind the stack,
* which doesn't work for assembly functions without unwind information. */
#include <windows.h>
#define checkasm_context CONTEXT
#define checkasm_save_context() RtlCaptureContext(&checkasm_context_buf)
#define checkasm_load_context() RtlRestoreContext(&checkasm_context_buf, NULL)
#else
#include <setjmp.h>
#define checkasm_context jmp_buf
#define checkasm_save_context() setjmp(checkasm_context_buf)
#define checkasm_load_context() longjmp(checkasm_context_buf, 1)
#endif
#include "include/common/attributes.h"
#include "include/common/intops.h"
......@@ -52,6 +66,8 @@ int checkasm_bench_func(void);
void checkasm_fail_func(const char *msg, ...);
void checkasm_update_bench(int iterations, uint64_t cycles);
void checkasm_report(const char *name, ...);
void checkasm_set_signal_handler_state(int enabled);
extern checkasm_context checkasm_context_buf;
/* float compare utilities */
int float_near_ulp(float a, float b, unsigned max_ulp);
......@@ -76,7 +92,9 @@ static void *func_ref, *func_new;
* the remaining arguments are the function parameters. Naming parameters
* is optional. */
#define declare_func(ret, ...)\
declare_new(ret, __VA_ARGS__) typedef ret func_type(__VA_ARGS__)
declare_new(ret, __VA_ARGS__)\
typedef ret func_type(__VA_ARGS__);\
checkasm_save_context()
/* Indicate that the current test has failed */
#define fail() checkasm_fail_func("%s:%d", __FILE__, __LINE__)
......@@ -85,7 +103,10 @@ static void *func_ref, *func_new;
#define report checkasm_report
/* Call the reference function */
#define call_ref(...) ((func_type *)func_ref)(__VA_ARGS__)
#define call_ref(...)\
(checkasm_set_signal_handler_state(1),\
((func_type *)func_ref)(__VA_ARGS__));\
checkasm_set_signal_handler_state(0)
#if HAVE_ASM
#if ARCH_X86
......@@ -153,14 +174,19 @@ void checkasm_stack_clobber(uint64_t clobber, ...);
(void *)checkasm_checked_call;
#define CLOB (UINT64_C(0xdeadbeefdeadbeef))
#define call_new(...)\
(checkasm_stack_clobber(CLOB, CLOB, CLOB, CLOB, CLOB, CLOB, CLOB,\
(checkasm_set_signal_handler_state(1),\
checkasm_stack_clobber(CLOB, CLOB, CLOB, CLOB, CLOB, CLOB, CLOB,\
CLOB, CLOB, CLOB, CLOB, CLOB, CLOB, CLOB,\
CLOB, CLOB, CLOB, CLOB, CLOB, CLOB, CLOB),\
checked_call(func_new, 0, 0, 0, 0, 0, __VA_ARGS__))
checked_call(func_new, 0, 0, 0, 0, 0, __VA_ARGS__));\
checkasm_set_signal_handler_state(0)
#elif ARCH_X86_32
#define declare_new(ret, ...)\
ret (*checked_call)(void *, __VA_ARGS__) = (void *)checkasm_checked_call;
#define call_new(...) checked_call(func_new, __VA_ARGS__)
#define call_new(...)\
(checkasm_set_signal_handler_state(1),\
checked_call(func_new, __VA_ARGS__));\
checkasm_set_signal_handler_state(0)
#elif ARCH_ARM
/* Use a dummy argument, to offset the real parameters by 2, not only 1.
* This makes sure that potential 8-byte-alignment of parameters is kept
......@@ -169,7 +195,10 @@ void checkasm_checked_call_vfp(void *func, int dummy, ...);
#define declare_new(ret, ...)\
ret (*checked_call)(void *, int dummy, __VA_ARGS__) =\
(void *)checkasm_checked_call_vfp;
#define call_new(...) checked_call(func_new, 0, __VA_ARGS__)
#define call_new(...)\
(checkasm_set_signal_handler_state(1),\
checked_call(func_new, 0, __VA_ARGS__));\
checkasm_set_signal_handler_state(0)
#elif ARCH_AARCH64 && !defined(__APPLE__)
void checkasm_stack_clobber(uint64_t clobber, ...);
#define declare_new(ret, ...)\
......@@ -178,19 +207,27 @@ void checkasm_stack_clobber(uint64_t clobber, ...);
(void *)checkasm_checked_call;
#define CLOB (UINT64_C(0xdeadbeefdeadbeef))
#define call_new(...)\
(checkasm_stack_clobber(CLOB, CLOB, CLOB, CLOB, CLOB, CLOB,\
(checkasm_set_signal_handler_state(1),\
checkasm_stack_clobber(CLOB, CLOB, CLOB, CLOB, CLOB, CLOB,\
CLOB, CLOB, CLOB, CLOB, CLOB, CLOB,\
CLOB, CLOB, CLOB, CLOB, CLOB, CLOB,\
CLOB, CLOB, CLOB, CLOB, CLOB),\
checked_call(func_new, 0, 0, 0, 0, 0, 0, 0, __VA_ARGS__))
checked_call(func_new, 0, 0, 0, 0, 0, 0, 0, __VA_ARGS__));\
checkasm_set_signal_handler_state(0)
#else
#define declare_new(ret, ...)
#define call_new(...) ((func_type *)func_new)(__VA_ARGS__)
#define call_new(...)\
(checkasm_set_signal_handler_state(1),\
((func_type *)func_new)(__VA_ARGS__));\
checkasm_set_signal_handler_state(0)
#endif
#else /* HAVE_ASM */
#define declare_new(ret, ...)
/* Call the function */
#define call_new(...) ((func_type *)func_new)(__VA_ARGS__)
#define call_new(...)\
(checkasm_set_signal_handler_state(1),\
((func_type *)func_new)(__VA_ARGS__));\
checkasm_set_signal_handler_state(0)
#endif /* HAVE_ASM */
/* Benchmark the function */
......@@ -198,6 +235,7 @@ void checkasm_stack_clobber(uint64_t clobber, ...);
#define bench_new(...)\
do {\
if (checkasm_bench_func()) {\
checkasm_set_signal_handler_state(1);\
func_type *tfunc = func_new;\
uint64_t tsum = 0;\
int ti, tcount = 0;\
......@@ -213,6 +251,7 @@ void checkasm_stack_clobber(uint64_t clobber, ...);
tcount++;\
}\
}\
checkasm_set_signal_handler_state(0);\
checkasm_update_bench(tcount, tsum);\
}\
} while (0)
......
......@@ -97,6 +97,11 @@ static void check_lpf_sb(loopfilter_sb_fn fn, const char *const name,
{
ALIGN_STK_32(pixel, c_dst_mem, 128 * 16,);
ALIGN_STK_32(pixel, a_dst_mem, 128 * 16,);
declare_func(void, pixel *dst, ptrdiff_t dst_stride, const uint32_t *mask,
const uint8_t (*l)[4], ptrdiff_t b4_stride,
const Av1FilterLUT *lut, int w HIGHBD_DECL_SUFFIX);
pixel *a_dst, *c_dst;
ptrdiff_t stride, b4_stride;
if (dir) {
......@@ -111,10 +116,6 @@ static void check_lpf_sb(loopfilter_sb_fn fn, const char *const name,
b4_stride = 2;
}
declare_func(void, pixel *dst, ptrdiff_t dst_stride, const uint32_t *mask,
const uint8_t (*l)[4], ptrdiff_t b4_stride,
const Av1FilterLUT *lut, int w HIGHBD_DECL_SUFFIX);
Av1FilterLUT lut;
const int sharp = rand() & 7;
for (int level = 0; level < 64; level++) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment