| # nocrash.m4 serial 5 | |
| dnl Copyright (C) 2005, 2009-2021 Free Software Foundation, Inc. | |
| dnl This file is free software; the Free Software Foundation | |
| dnl gives unlimited permission to copy and/or distribute it, | |
| dnl with or without modifications, as long as this notice is preserved. | |
| dnl Based on libsigsegv, from Bruno Haible and Paolo Bonzini. | |
| AC_PREREQ([2.13]) | |
| dnl Expands to some code for use in .c programs that will cause the configure | |
| dnl test to exit instead of crashing. This is useful to avoid triggering | |
| dnl action from a background debugger and to avoid core dumps. | |
| dnl Usage: ... | |
| dnl ]GL_NOCRASH[ | |
| dnl ... | |
| dnl int main() { nocrash_init(); ... } | |
| AC_DEFUN([GL_NOCRASH],[[ | |
| #include <stdlib.h> | |
| #if defined __MACH__ && defined __APPLE__ | |
| /* Avoid a crash on Mac OS X. */ | |
| #include <mach/mach.h> | |
| #include <mach/mach_error.h> | |
| #include <mach/thread_status.h> | |
| #include <mach/exception.h> | |
| #include <mach/task.h> | |
| #include <pthread.h> | |
| /* The exception port on which our thread listens. */ | |
| static mach_port_t our_exception_port; | |
| /* The main function of the thread listening for exceptions of type | |
| EXC_BAD_ACCESS. */ | |
| static void * | |
| mach_exception_thread (void *arg) | |
| { | |
| /* Buffer for a message to be received. */ | |
| struct { | |
| mach_msg_header_t head; | |
| mach_msg_body_t msgh_body; | |
| char data[1024]; | |
| } msg; | |
| mach_msg_return_t retval; | |
| /* Wait for a message on the exception port. */ | |
| retval = mach_msg (&msg.head, MACH_RCV_MSG | MACH_RCV_LARGE, 0, sizeof (msg), | |
| our_exception_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); | |
| if (retval != MACH_MSG_SUCCESS) | |
| abort (); | |
| exit (1); | |
| } | |
| static void | |
| nocrash_init (void) | |
| { | |
| mach_port_t self = mach_task_self (); | |
| /* Allocate a port on which the thread shall listen for exceptions. */ | |
| if (mach_port_allocate (self, MACH_PORT_RIGHT_RECEIVE, &our_exception_port) | |
| == KERN_SUCCESS) { | |
| /* See https://web.mit.edu/darwin/src/modules/xnu/osfmk/man/mach_port_insert_right.html. */ | |
| if (mach_port_insert_right (self, our_exception_port, our_exception_port, | |
| MACH_MSG_TYPE_MAKE_SEND) | |
| == KERN_SUCCESS) { | |
| /* The exceptions we want to catch. Only EXC_BAD_ACCESS is interesting | |
| for us. */ | |
| exception_mask_t mask = EXC_MASK_BAD_ACCESS; | |
| /* Create the thread listening on the exception port. */ | |
| pthread_attr_t attr; | |
| pthread_t thread; | |
| if (pthread_attr_init (&attr) == 0 | |
| && pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED) == 0 | |
| && pthread_create (&thread, &attr, mach_exception_thread, NULL) == 0) { | |
| pthread_attr_destroy (&attr); | |
| /* Replace the exception port info for these exceptions with our own. | |
| Note that we replace the exception port for the entire task, not only | |
| for a particular thread. This has the effect that when our exception | |
| port gets the message, the thread specific exception port has already | |
| been asked, and we don't need to bother about it. | |
| See https://web.mit.edu/darwin/src/modules/xnu/osfmk/man/task_set_exception_ports.html. */ | |
| task_set_exception_ports (self, mask, our_exception_port, | |
| EXCEPTION_DEFAULT, MACHINE_THREAD_STATE); | |
| } | |
| } | |
| } | |
| } | |
| #elif defined _WIN32 && ! defined __CYGWIN__ | |
| /* Avoid a crash on native Windows. */ | |
| #define WIN32_LEAN_AND_MEAN | |
| #include <windows.h> | |
| #include <winerror.h> | |
| static LONG WINAPI | |
| exception_filter (EXCEPTION_POINTERS *ExceptionInfo) | |
| { | |
| switch (ExceptionInfo->ExceptionRecord->ExceptionCode) | |
| { | |
| case EXCEPTION_ACCESS_VIOLATION: | |
| case EXCEPTION_IN_PAGE_ERROR: | |
| case EXCEPTION_STACK_OVERFLOW: | |
| case EXCEPTION_GUARD_PAGE: | |
| case EXCEPTION_PRIV_INSTRUCTION: | |
| case EXCEPTION_ILLEGAL_INSTRUCTION: | |
| case EXCEPTION_DATATYPE_MISALIGNMENT: | |
| case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: | |
| case EXCEPTION_NONCONTINUABLE_EXCEPTION: | |
| exit (1); | |
| } | |
| return EXCEPTION_CONTINUE_SEARCH; | |
| } | |
| static void | |
| nocrash_init (void) | |
| { | |
| SetUnhandledExceptionFilter ((LPTOP_LEVEL_EXCEPTION_FILTER) exception_filter); | |
| } | |
| #else | |
| /* Avoid a crash on POSIX systems. */ | |
| #include <signal.h> | |
| #include <unistd.h> | |
| /* A POSIX signal handler. */ | |
| static void | |
| exception_handler (int sig) | |
| { | |
| _exit (1); | |
| } | |
| static void | |
| nocrash_init (void) | |
| { | |
| #ifdef SIGSEGV | |
| signal (SIGSEGV, exception_handler); | |
| #endif | |
| #ifdef SIGBUS | |
| signal (SIGBUS, exception_handler); | |
| #endif | |
| } | |
| #endif | |
| ]]) |