132 lines
4.4 KiB
Plaintext
132 lines
4.4 KiB
Plaintext
|
# nocrash.m4 serial 5
|
||
|
dnl Copyright (C) 2005, 2009-2023 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
|
||
|
]])
|